1use super::{
2 CommandBuffer, CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState,
3 CommandBufferSubmitInfo, CommandBufferUsage, SecondaryCommandBufferResourcesUsage,
4 SemaphoreSubmitInfo, SubmitInfo,
5};
6use crate::{
7 buffer::Buffer,
8 device::{Device, DeviceOwned, Queue},
9 image::{Image, ImageLayout},
10 swapchain::Swapchain,
11 sync::{
12 future::{
13 now, queue_submit, AccessCheckError, AccessError, GpuFuture, NowFuture,
14 SubmitAnyBuilder,
15 },
16 PipelineStages,
17 },
18 DeviceSize, SafeDeref, Validated, ValidationError, VulkanError, VulkanObject,
19};
20use parking_lot::{Mutex, MutexGuard};
21use std::{
22 borrow::Cow,
23 error::Error,
24 fmt::{Debug, Display, Error as FmtError, Formatter},
25 ops::Range,
26 sync::{
27 atomic::{AtomicBool, Ordering},
28 Arc,
29 },
30 thread,
31};
32
33pub unsafe trait PrimaryCommandBufferAbstract:
34 VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
35{
36 fn as_raw(&self) -> &CommandBuffer;
38
39 fn queue_family_index(&self) -> u32;
41
42 fn usage(&self) -> CommandBufferUsage;
44
45 #[inline]
68 fn execute(
69 self: Arc<Self>,
70 queue: Arc<Queue>,
71 ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError>
72 where
73 Self: Sized + 'static,
74 {
75 let device = queue.device().clone();
76 self.execute_after(now(device), queue)
77 }
78
79 fn execute_after<F>(
106 self: Arc<Self>,
107 future: F,
108 queue: Arc<Queue>,
109 ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError>
110 where
111 Self: Sized + 'static,
112 F: GpuFuture,
113 {
114 assert_eq!(self.device().handle(), future.device().handle());
115
116 if !future.queue_change_allowed() {
117 assert_eq!(future.queue().unwrap(), queue);
118 }
119
120 Ok(CommandBufferExecFuture {
121 previous: future,
122 command_buffer: self,
123 queue,
124 submitted: Mutex::new(false),
125 finished: AtomicBool::new(false),
126 })
127 }
128
129 #[doc(hidden)]
130 fn state(&self) -> MutexGuard<'_, CommandBufferState>;
131
132 #[doc(hidden)]
133 fn resources_usage(&self) -> &CommandBufferResourcesUsage;
134}
135
136impl Debug for dyn PrimaryCommandBufferAbstract {
137 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
138 Debug::fmt(&self.handle(), f)
139 }
140}
141
142unsafe impl<T> PrimaryCommandBufferAbstract for T
143where
144 T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
145 T::Target: PrimaryCommandBufferAbstract,
146{
147 fn as_raw(&self) -> &CommandBuffer {
148 (**self).as_raw()
149 }
150
151 fn queue_family_index(&self) -> u32 {
152 (**self).queue_family_index()
153 }
154
155 fn usage(&self) -> CommandBufferUsage {
156 (**self).usage()
157 }
158
159 fn state(&self) -> MutexGuard<'_, CommandBufferState> {
160 (**self).state()
161 }
162
163 fn resources_usage(&self) -> &CommandBufferResourcesUsage {
164 (**self).resources_usage()
165 }
166}
167
168pub unsafe trait SecondaryCommandBufferAbstract:
169 VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
170{
171 fn as_raw(&self) -> &CommandBuffer;
173
174 fn usage(&self) -> CommandBufferUsage;
176
177 fn inheritance_info(&self) -> &CommandBufferInheritanceInfo;
180
181 fn lock_record(&self) -> Result<(), Box<ValidationError>>;
186
187 unsafe fn unlock(&self);
193
194 #[doc(hidden)]
195 fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage;
196}
197
198unsafe impl<T> SecondaryCommandBufferAbstract for T
199where
200 T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
201 T::Target: SecondaryCommandBufferAbstract,
202{
203 fn as_raw(&self) -> &CommandBuffer {
204 (**self).as_raw()
205 }
206
207 fn usage(&self) -> CommandBufferUsage {
208 (**self).usage()
209 }
210
211 fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
212 (**self).inheritance_info()
213 }
214
215 fn lock_record(&self) -> Result<(), Box<ValidationError>> {
216 (**self).lock_record()
217 }
218
219 unsafe fn unlock(&self) {
220 unsafe { (**self).unlock() };
221 }
222
223 fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
224 (**self).resources_usage()
225 }
226}
227
228#[derive(Debug)]
231#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
232pub struct CommandBufferExecFuture<F>
233where
234 F: GpuFuture,
235{
236 previous: F,
237 command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
238 queue: Arc<Queue>,
239 submitted: Mutex<bool>,
243 finished: AtomicBool,
244}
245
246impl<F> CommandBufferExecFuture<F>
247where
248 F: GpuFuture,
249{
250 unsafe fn build_submission_impl(&self) -> Result<SubmitAnyBuilder, Validated<VulkanError>> {
253 Ok(match unsafe { self.previous.build_submission() }? {
254 SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer(
255 SubmitInfo {
256 command_buffers: vec![CommandBufferSubmitInfo::new(
257 self.command_buffer.clone(),
258 )],
259 ..Default::default()
260 },
261 None,
262 ),
263 SubmitAnyBuilder::SemaphoresWait(semaphores) => {
264 SubmitAnyBuilder::CommandBuffer(
265 SubmitInfo {
266 wait_semaphores: semaphores
267 .into_iter()
268 .map(|semaphore| {
269 SemaphoreSubmitInfo {
270 stages: PipelineStages::ALL_COMMANDS,
272 ..SemaphoreSubmitInfo::new(semaphore)
273 }
274 })
275 .collect(),
276 command_buffers: vec![CommandBufferSubmitInfo::new(
277 self.command_buffer.clone(),
278 )],
279 ..Default::default()
280 },
281 None,
282 )
283 }
284 SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
285 submit_info
287 .command_buffers
288 .push(CommandBufferSubmitInfo::new(self.command_buffer.clone()));
289 SubmitAnyBuilder::CommandBuffer(submit_info, fence)
290 }
291 SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => {
292 unimplemented!() }
298 })
299 }
300}
301
302unsafe impl<F> GpuFuture for CommandBufferExecFuture<F>
303where
304 F: GpuFuture,
305{
306 fn cleanup_finished(&mut self) {
307 self.previous.cleanup_finished();
308 }
309
310 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, Validated<VulkanError>> {
311 if *self.submitted.lock() {
312 return Ok(SubmitAnyBuilder::Empty);
313 }
314
315 unsafe { self.build_submission_impl() }
316 }
317
318 fn flush(&self) -> Result<(), Validated<VulkanError>> {
319 let mut submitted = self.submitted.lock();
320
321 if *submitted {
322 return Ok(());
323 }
324
325 match unsafe { self.build_submission_impl() }? {
326 SubmitAnyBuilder::Empty => {}
327 SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
328 unsafe { queue_submit(&self.queue, submit_info, fence, &self.previous) }.unwrap();
329 }
330 _ => unreachable!(),
331 };
332
333 *submitted = true;
335 Ok(())
336 }
337
338 unsafe fn signal_finished(&self) {
339 if !self.finished.swap(true, Ordering::SeqCst) {
340 let resource_usage = self.command_buffer.resources_usage();
341
342 for usage in &resource_usage.buffers {
343 let mut state = usage.buffer.state();
344
345 for (range, range_usage) in usage.ranges.iter() {
346 if range_usage.mutable {
347 unsafe { state.gpu_write_unlock(range.clone()) };
348 } else {
349 unsafe { state.gpu_read_unlock(range.clone()) };
350 }
351 }
352 }
353
354 for usage in &resource_usage.images {
355 let mut state = usage.image.state();
356
357 for (range, range_usage) in usage.ranges.iter() {
358 if range_usage.mutable {
359 unsafe { state.gpu_write_unlock(range.clone()) };
360 } else {
361 unsafe { state.gpu_read_unlock(range.clone()) };
362 }
363 }
364 }
365
366 unsafe { self.command_buffer.state().set_submit_finished() };
367 }
368
369 unsafe { self.previous.signal_finished() };
370 }
371
372 fn queue_change_allowed(&self) -> bool {
373 false
374 }
375
376 fn queue(&self) -> Option<Arc<Queue>> {
377 Some(self.queue.clone())
378 }
379
380 fn check_buffer_access(
381 &self,
382 buffer: &Buffer,
383 range: Range<DeviceSize>,
384 exclusive: bool,
385 queue: &Queue,
386 ) -> Result<(), AccessCheckError> {
387 let resources_usage = self.command_buffer.resources_usage();
388 let usage = match resources_usage.buffer_indices.get(buffer) {
389 Some(&index) => &resources_usage.buffers[index],
390 None => return Err(AccessCheckError::Unknown),
391 };
392
393 let result = usage
396 .ranges
397 .range(&range)
398 .try_fold((), |_, (_range, range_usage)| {
399 if !range_usage.mutable && exclusive {
400 Err(AccessCheckError::Unknown)
401 } else {
402 Ok(())
403 }
404 });
405
406 match result {
407 Ok(()) => Ok(()),
408 Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
409 Err(AccessCheckError::Unknown) => self
410 .previous
411 .check_buffer_access(buffer, range, exclusive, queue),
412 }
413 }
414
415 fn check_image_access(
416 &self,
417 image: &Image,
418 range: Range<DeviceSize>,
419 exclusive: bool,
420 expected_layout: ImageLayout,
421 queue: &Queue,
422 ) -> Result<(), AccessCheckError> {
423 let resources_usage = self.command_buffer.resources_usage();
424 let usage = match resources_usage.image_indices.get(image) {
425 Some(&index) => &resources_usage.images[index],
426 None => return Err(AccessCheckError::Unknown),
427 };
428
429 let result = usage
432 .ranges
433 .range(&range)
434 .try_fold((), |_, (_range, range_usage)| {
435 if expected_layout != ImageLayout::Undefined
436 && range_usage.final_layout != expected_layout
437 {
438 return Err(AccessCheckError::Denied(
439 AccessError::UnexpectedImageLayout {
440 allowed: range_usage.final_layout,
441 requested: expected_layout,
442 },
443 ));
444 }
445
446 if !range_usage.mutable && exclusive {
447 Err(AccessCheckError::Unknown)
448 } else {
449 Ok(())
450 }
451 });
452
453 match result {
454 Ok(()) => Ok(()),
455 Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
456 Err(AccessCheckError::Unknown) => {
457 self.previous
458 .check_image_access(image, range, exclusive, expected_layout, queue)
459 }
460 }
461 }
462
463 #[inline]
464 fn check_swapchain_image_acquired(
465 &self,
466 swapchain: &Swapchain,
467 image_index: u32,
468 _before: bool,
469 ) -> Result<(), AccessCheckError> {
470 self.previous
471 .check_swapchain_image_acquired(swapchain, image_index, false)
472 }
473}
474
475unsafe impl<F> DeviceOwned for CommandBufferExecFuture<F>
476where
477 F: GpuFuture,
478{
479 fn device(&self) -> &Arc<Device> {
480 self.command_buffer.device()
481 }
482}
483
484impl<F> Drop for CommandBufferExecFuture<F>
485where
486 F: GpuFuture,
487{
488 fn drop(&mut self) {
489 if !*self.finished.get_mut() && !thread::panicking() {
490 self.flush().unwrap();
492 self.queue.with(|mut q| q.wait_idle()).unwrap();
494
495 unsafe {
496 self.signal_finished();
497 }
498 }
499 }
500}
501
502#[derive(Clone, Debug, PartialEq, Eq)]
504pub enum CommandBufferExecError {
505 AccessError {
507 error: AccessError,
508 command_name: Cow<'static, str>,
509 command_param: Cow<'static, str>,
510 command_offset: usize,
511 },
512
513 OneTimeSubmitAlreadySubmitted,
516
517 ExclusiveAlreadyInUse,
520 }
522
523impl Error for CommandBufferExecError {
524 fn source(&self) -> Option<&(dyn Error + 'static)> {
525 match self {
526 CommandBufferExecError::AccessError { error, .. } => Some(error),
527 _ => None,
528 }
529 }
530}
531
532impl Display for CommandBufferExecError {
533 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
534 match self {
535 CommandBufferExecError::AccessError {
536 error: _,
537 command_name,
538 command_offset,
539 command_param,
540 } => write!(
541 f,
542 "access to a resource has been denied on command {} (offset: {}, param: {})",
543 command_name, command_offset, command_param,
544 ),
545 CommandBufferExecError::OneTimeSubmitAlreadySubmitted => write!(
546 f,
547 "the command buffer or one of the secondary command buffers it executes was \
548 created with the \"one time submit\" flag, but has already been submitted in \
549 the past",
550 ),
551 CommandBufferExecError::ExclusiveAlreadyInUse => write!(
552 f,
553 "the command buffer or one of the secondary command buffers it executes is \
554 already in use was not created with the \"concurrent\" flag"
555 ),
556 }
557 }
558}