1
2use crate::prelude::*;
3use std::{
4 fmt::{self, Debug, Formatter},
5 ptr::null,
6 sync::{
7 Arc,
8 atomic::{
9 AtomicBool,
10 AtomicUsize,
11 Ordering,
12 },
13 Mutex,
14 MutexGuard,
15 },
16};
17
18pub struct VulkanCommandPool {
20 pub device: Arc<VulkanDevice>,
22
23 pub(crate) pool: Mutex<VkCommandPool>,
25
26 pub(crate) cmd_buffers: Vec<VkCommandBuffer>,
28
29 pub index_of_buffer: AtomicUsize,
31
32 pub submit_fence: Arc<VulkanFence>,
34}
35
36unsafe impl Send for VulkanCommandPool {}
37unsafe impl Sync for VulkanCommandPool {}
38
39impl VulkanCommandPool {
40 pub fn new(device: Arc<VulkanDevice>, num_buffers: usize) -> Result<Self, VulkanError> {
42 let vkcore = device.vkcore.clone();
43 let vk_device = device.get_vk_device();
44 let pool_ci = VkCommandPoolCreateInfo {
45 sType: VkStructureType::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
46 pNext: null(),
47 queueFamilyIndex: device.get_queue_family_index(),
48 flags:
49 VkCommandPoolCreateFlagBits::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as VkCommandPoolCreateFlags |
50 VkCommandPoolCreateFlagBits::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT as VkCommandPoolCreateFlags,
51 };
52 let mut pool: VkCommandPool = null();
53 vkcore.vkCreateCommandPool(vk_device, &pool_ci, null(), &mut pool)?;
54 let cmd_buffers_ci = VkCommandBufferAllocateInfo {
55 sType: VkStructureType::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
56 pNext: null(),
57 commandPool: pool,
58 level: VkCommandBufferLevel::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
59 commandBufferCount: num_buffers as u32,
60 };
61 let pool = Mutex::new(pool);
62 let mut cmd_buffers: Vec<VkCommandBuffer> = Vec::with_capacity(num_buffers);
63 vkcore.vkAllocateCommandBuffers(vk_device, &cmd_buffers_ci, cmd_buffers.as_mut_ptr())?;
64 unsafe {cmd_buffers.set_len(num_buffers)};
65 let submit_fence = Arc::new(VulkanFence::new(device.clone())?);
66 Ok(Self{
67 device,
68 pool,
69 index_of_buffer: AtomicUsize::new(0),
70 cmd_buffers,
71 submit_fence,
72 })
73 }
74
75 pub(crate) fn use_pool<'a>(&'a self, rt_props: Option<Arc<RenderTargetProps>>) -> Result<VulkanCommandPoolInUse<'a>, VulkanError> {
77 let pool_lock = self.pool.lock().unwrap();
78 let begin_info = VkCommandBufferBeginInfo {
79 sType: VkStructureType::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
80 pNext: null(),
81 flags: 0,
82 pInheritanceInfo: null(),
83 };
84 let buffer_index = self.index_of_buffer.fetch_add(1, Ordering::Relaxed) % self.cmd_buffers.len();
85 self.device.vkcore.vkResetCommandBuffer(self.cmd_buffers[buffer_index], 0)?;
86 self.device.vkcore.vkBeginCommandBuffer(self.cmd_buffers[buffer_index], &begin_info)?;
87 VulkanCommandPoolInUse::new(self, pool_lock, self.cmd_buffers[buffer_index], rt_props)
88 }
89
90 pub fn wait_for_submit(&self, timeout: u64) -> Result<(), VulkanError> {
92 self.submit_fence.wait(timeout)?;
93 self.submit_fence.unsignal()?;
94 Ok(())
95 }
96}
97
98impl Debug for VulkanCommandPool {
99 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
100 f.debug_struct("VulkanCommandPool")
101 .field("pool", &self.pool)
102 .field("cmd_buffers", &self.cmd_buffers)
103 .field("index_of_buffer", &self.index_of_buffer)
104 .field("submit_fence", &self.submit_fence)
105 .finish()
106 }
107}
108
109impl Drop for VulkanCommandPool {
110 fn drop(&mut self) {
111 let vkcore = self.device.vkcore.clone();
112 proceed_run(self.submit_fence.wait(u64::MAX));
113 proceed_run(self.submit_fence.unsignal());
114 proceed_run(vkcore.vkDestroyCommandPool(self.device.get_vk_device(), *self.pool.lock().unwrap(), null()));
115 }
116}
117
118pub struct VulkanCommandPoolInUse<'a> {
120 pub device: Arc<VulkanDevice>,
122
123 pub(crate) cmdbuf: VkCommandBuffer,
125
126 pub(crate) pool_lock: MutexGuard<'a, VkCommandPool>,
128
129 pub rt_props: Option<Arc<RenderTargetProps>>,
131
132 pub submit_fence: Arc<VulkanFence>,
134
135 pub(crate) ended: AtomicBool,
137
138 pub submitted: AtomicBool,
140}
141
142impl<'a> VulkanCommandPoolInUse<'a> {
143 fn new(cmdpool: &VulkanCommandPool, pool_lock: MutexGuard<'a, VkCommandPool>, cmdbuf: VkCommandBuffer, rt_props: Option<Arc<RenderTargetProps>>) -> Result<Self, VulkanError> {
145 let device = cmdpool.device.clone();
146 let submit_fence = cmdpool.submit_fence.clone();
147 Ok(Self {
148 device,
149 cmdbuf,
150 pool_lock,
151 rt_props,
152 submit_fence,
153 ended: AtomicBool::new(false),
154 submitted: AtomicBool::new(false),
155 })
156 }
157
158 pub(crate) fn get_vk_cmdbuf(&self) -> VkCommandBuffer {
160 self.cmdbuf
161 }
162
163 pub fn end_cmd(&self) -> Result<(), VulkanError> {
165 let vkcore = self.device.vkcore.clone();
166 if !self.ended.fetch_or(true, Ordering::AcqRel) {
167 vkcore.vkEndCommandBuffer(self.cmdbuf).inspect_err(|_|{
168 self.ended.store(false, Ordering::Release);
169 })?;
170 Ok(())
171 } else {
172 panic!("Duplicated call to `VulkanCommandPoolInUse::end()`")
173 }
174 }
175
176 pub fn submit(&self) -> Result<(), VulkanError> {
178 let vkcore = self.device.vkcore.clone();
179 if !self.ended.load(Ordering::Acquire) {
180 self.end_cmd()?;
181 }
182 if !self.submitted.fetch_or(true, Ordering::AcqRel) {
183 let wait_stage = [VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT as VkPipelineStageFlags];
184 let cmd_buffers = [self.cmdbuf];
185
186 let (acquire_semaphores, release_semaphores) = if let Some(rt_props) = &self.rt_props {
187 (
188 vec![rt_props.acquire_semaphore.lock().unwrap().get_vk_semaphore()],
189 vec![rt_props.release_semaphore.get_vk_semaphore()]
190 )
191 } else {
192 (vec![], vec![])
193 };
194 let submit_info = VkSubmitInfo {
195 sType: VkStructureType::VK_STRUCTURE_TYPE_SUBMIT_INFO,
196 pNext: null(),
197 waitSemaphoreCount: acquire_semaphores.len() as u32,
198 pWaitSemaphores: acquire_semaphores.as_ptr(),
199 pWaitDstStageMask: wait_stage.as_ptr(),
200 commandBufferCount: 1,
201 pCommandBuffers: cmd_buffers.as_ptr(),
202 signalSemaphoreCount: release_semaphores.len() as u32,
203 pSignalSemaphores: release_semaphores.as_ptr(),
204 };
205 let submits = [submit_info];
206 self.submit_fence.wait(u64::MAX)?;
207 self.submit_fence.unsignal()?;
208 vkcore.vkQueueSubmit(self.device.get_vk_queue(), submits.len() as u32, submits.as_ptr(), self.submit_fence.get_vk_fence()).inspect_err(|_|{
209 self.submitted.store(false, Ordering::Release);
210 })?;
211 self.submit_fence.set_is_being_signaled();
212 Ok(())
213 } else {
214 panic!("Duplicated call to `VulkanCommandPoolInUse::submit()`, please set the `submitted` member to false to re-submit again if you wish.")
215 }
216 }
217
218 pub fn end(self) {}
220}
221
222impl Debug for VulkanCommandPoolInUse<'_> {
223 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
224 f.debug_struct("VulkanCommandPoolInUse")
225 .field("cmdbuf", &self.cmdbuf)
226 .field("pool_lock", &self.pool_lock)
227 .field("rt_props", &self.rt_props)
228 .field("submit_fence", &self.submit_fence)
229 .field("ended", &self.ended)
230 .field("submitted", &self.submitted)
231 .finish()
232 }
233}
234
235impl Drop for VulkanCommandPoolInUse<'_> {
236 fn drop(&mut self) {
237 if !self.submitted.load(Ordering::Acquire) {
238 proceed_run(self.submit())
239 }
240 }
241}