1 // Copyright (c) 2022 The Vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! The standard command buffer and builder. 11 //! 12 //! Using `CommandBufferBuilder`, you must manually record synchronization commands to ensure 13 //! correct operation. 14 15 #![allow(dead_code)] 16 17 pub use self::builder::*; 18 use super::{ 19 allocator::{CommandBufferAlloc, StandardCommandBufferAlloc}, 20 CommandBufferExecError, CommandBufferInheritanceInfo, CommandBufferState, CommandBufferUsage, 21 }; 22 use crate::{ 23 device::{Device, DeviceOwned}, 24 VulkanObject, 25 }; 26 use parking_lot::Mutex; 27 use std::{ 28 any::Any, 29 sync::{ 30 atomic::{AtomicBool, Ordering}, 31 Arc, 32 }, 33 }; 34 35 mod builder; 36 37 /// A command buffer that is finished recording, and can be submitted to a queue. 38 pub struct PrimaryCommandBuffer<A = StandardCommandBufferAlloc> 39 where 40 A: CommandBufferAlloc, 41 { 42 alloc: A, 43 _usage: CommandBufferUsage, 44 _resources: Vec<Box<dyn Any + Send + Sync>>, 45 46 _state: Mutex<CommandBufferState>, 47 } 48 49 unsafe impl<A> VulkanObject for PrimaryCommandBuffer<A> 50 where 51 A: CommandBufferAlloc, 52 { 53 type Handle = ash::vk::CommandBuffer; 54 55 #[inline] handle(&self) -> Self::Handle56 fn handle(&self) -> Self::Handle { 57 self.alloc.inner().handle() 58 } 59 } 60 61 unsafe impl<A> DeviceOwned for PrimaryCommandBuffer<A> 62 where 63 A: CommandBufferAlloc, 64 { 65 #[inline] device(&self) -> &Arc<Device>66 fn device(&self) -> &Arc<Device> { 67 self.alloc.device() 68 } 69 } 70 71 /// A command buffer that is finished recording, and can be executed within a primary command 72 /// buffer by calling [`execute_commands`]. 73 /// 74 /// [`execute_commands`]: CommandBufferBuilder::execute_commands 75 pub struct SecondaryCommandBuffer<A = StandardCommandBufferAlloc> 76 where 77 A: CommandBufferAlloc, 78 { 79 alloc: A, 80 inheritance_info: CommandBufferInheritanceInfo, 81 usage: CommandBufferUsage, 82 _resources: Vec<Box<dyn Any + Send + Sync>>, 83 84 submit_state: SubmitState, 85 } 86 87 unsafe impl<A> VulkanObject for SecondaryCommandBuffer<A> 88 where 89 A: CommandBufferAlloc, 90 { 91 type Handle = ash::vk::CommandBuffer; 92 93 #[inline] handle(&self) -> Self::Handle94 fn handle(&self) -> Self::Handle { 95 self.alloc.inner().handle() 96 } 97 } 98 99 unsafe impl<A> DeviceOwned for SecondaryCommandBuffer<A> 100 where 101 A: CommandBufferAlloc, 102 { 103 #[inline] device(&self) -> &Arc<Device>104 fn device(&self) -> &Arc<Device> { 105 self.alloc.device() 106 } 107 } 108 109 impl<A> SecondaryCommandBuffer<A> 110 where 111 A: CommandBufferAlloc, 112 { 113 #[inline] inheritance_info(&self) -> &CommandBufferInheritanceInfo114 pub fn inheritance_info(&self) -> &CommandBufferInheritanceInfo { 115 &self.inheritance_info 116 } 117 lock_record(&self) -> Result<(), CommandBufferExecError>118 pub fn lock_record(&self) -> Result<(), CommandBufferExecError> { 119 match self.submit_state { 120 SubmitState::OneTime { 121 ref already_submitted, 122 } => { 123 let was_already_submitted = already_submitted.swap(true, Ordering::Acquire); 124 if was_already_submitted { 125 return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted); 126 } 127 } 128 SubmitState::ExclusiveUse { ref in_use } => { 129 let already_in_use = in_use.swap(true, Ordering::Acquire); 130 if already_in_use { 131 return Err(CommandBufferExecError::ExclusiveAlreadyInUse); 132 } 133 } 134 SubmitState::Concurrent => (), 135 }; 136 137 Ok(()) 138 } 139 unlock(&self)140 pub unsafe fn unlock(&self) { 141 match self.submit_state { 142 SubmitState::OneTime { 143 ref already_submitted, 144 } => { 145 debug_assert!(already_submitted.load(Ordering::Relaxed)); 146 } 147 SubmitState::ExclusiveUse { ref in_use } => { 148 let old_val = in_use.swap(false, Ordering::Release); 149 debug_assert!(old_val); 150 } 151 SubmitState::Concurrent => (), 152 }; 153 } 154 } 155 156 /// Whether the command buffer can be submitted. 157 #[derive(Debug)] 158 enum SubmitState { 159 /// The command buffer was created with the "SimultaneousUse" flag. Can always be submitted at 160 /// any time. 161 Concurrent, 162 163 /// The command buffer can only be submitted once simultaneously. 164 ExclusiveUse { 165 /// True if the command buffer is current in use by the GPU. 166 in_use: AtomicBool, 167 }, 168 169 /// The command buffer can only ever be submitted once. 170 OneTime { 171 /// True if the command buffer has already been submitted once and can be no longer be 172 /// submitted. 173 already_submitted: AtomicBool, 174 }, 175 } 176