vk_graph/driver/
cmd_buf.rs1use {
4 super::{DriverError, device::Device},
5 ash::vk,
6 derive_builder::{Builder, UninitializedFieldError},
7 log::{error, trace, warn},
8 std::{fmt::Debug, slice, thread::panicking},
9};
10
11#[derive(Debug)]
16#[read_only::cast]
17pub struct CommandBuffer {
18 #[readonly]
22 pub device: Device,
23
24 droppables: Vec<Box<dyn Debug + Send + 'static>>,
25
26 #[readonly]
30 pub fence: vk::Fence,
31
32 #[readonly]
36 pub handle: vk::CommandBuffer,
37
38 #[readonly]
40 pub info: CommandBufferInfo,
41
42 pub(crate) pool: vk::CommandPool,
43}
44
45impl CommandBuffer {
46 #[profiling::function]
48 pub fn create(device: &Device, info: CommandBufferInfo) -> Result<Self, DriverError> {
49 let device = device.clone();
50
51 let pool = unsafe {
52 device.create_command_pool(
53 &vk::CommandPoolCreateInfo::default()
54 .flags(
55 vk::CommandPoolCreateFlags::TRANSIENT
56 | vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER,
57 )
58 .queue_family_index(info.queue_family_index),
59 None,
60 )
61 }
62 .map_err(|err| {
63 warn!("unable to create command pool: {err}");
64
65 match err {
66 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
67 DriverError::OutOfMemory
68 }
69 _ => DriverError::Unsupported,
70 }
71 })?;
72
73 let handle = unsafe {
74 device.allocate_command_buffers(
75 &vk::CommandBufferAllocateInfo::default()
76 .command_buffer_count(1)
77 .command_pool(pool)
78 .level(vk::CommandBufferLevel::PRIMARY),
79 )
80 }
81 .map_err(|err| {
82 warn!("unable to allocate command buffer: {err}");
83
84 match err {
85 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
86 DriverError::OutOfMemory
87 }
88 _ => DriverError::Unsupported,
89 }
90 })?[0];
91
92 let fence = Device::create_fence(&device, false)?;
93
94 Ok(Self {
95 device,
96 droppables: vec![],
97 fence,
98 handle,
99 info,
100 pool,
101 })
102 }
103
104 pub fn drop_after_executed(&mut self, x: impl Debug + Send + 'static) {
106 self.droppables.push(Box::new(x));
107 }
108
109 #[profiling::function]
111 fn drop_fenced(&mut self) {
112 if !self.droppables.is_empty() {
113 trace!("dropping {} shared references", self.droppables.len());
114 }
115
116 self.droppables.clear();
117 }
118
119 #[profiling::function]
123 pub fn has_executed(&self) -> Result<bool, DriverError> {
124 let res = unsafe { self.device.get_fence_status(self.fence) };
125
126 match res {
127 Ok(status) => Ok(status),
128 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
129 error!("invalid device state: lost");
130
131 Err(DriverError::InvalidData)
132 }
133 Err(err) => {
134 error!("unable to get fence status: {err}");
137
138 Err(DriverError::InvalidData)
139 }
140 }
141 }
142
143 #[profiling::function]
148 pub fn wait_until_executed(&mut self) -> Result<(), DriverError> {
149 if self.droppables.is_empty() {
150 return Ok(());
151 }
152
153 Device::wait_for_fence(&self.device, &self.fence)?;
154
155 self.drop_fenced();
156
157 Ok(())
158 }
159}
160
161impl Drop for CommandBuffer {
162 #[profiling::function]
163 fn drop(&mut self) {
164 if panicking() {
165 return;
166 }
167
168 if self.wait_until_executed().is_err() {
169 return;
170 }
171
172 unsafe {
173 self.device
174 .free_command_buffers(self.pool, slice::from_ref(&self.handle));
175 self.device.destroy_command_pool(self.pool, None);
176 self.device.destroy_fence(self.fence, None);
177 }
178 }
179}
180
181#[derive(Builder, Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
183#[builder(
184 build_fn(private, name = "fallible_build", error = "UninitializedFieldError"),
185 derive(Clone, Copy, Debug),
186 pattern = "owned"
187)]
188pub struct CommandBufferInfo {
189 pub queue_family_index: u32,
193}
194
195impl CommandBufferInfo {
196 pub fn new(queue_family_index: u32) -> Self {
198 Self { queue_family_index }
199 }
200}
201
202impl CommandBufferInfo {
203 pub fn builder() -> CommandBufferInfoBuilder {
205 Default::default()
206 }
207
208 pub fn into_builder(self) -> CommandBufferInfoBuilder {
210 CommandBufferInfoBuilder {
211 queue_family_index: Some(self.queue_family_index),
212 }
213 }
214
215 #[deprecated = "use into_builder function"]
216 #[doc(hidden)]
217 pub fn to_builder(self) -> CommandBufferInfoBuilder {
218 self.into_builder()
219 }
220}
221
222impl From<CommandBufferInfoBuilder> for CommandBufferInfo {
223 fn from(info: CommandBufferInfoBuilder) -> Self {
224 info.build()
225 }
226}
227
228impl CommandBufferInfoBuilder {
229 #[inline(always)]
231 pub fn build(self) -> CommandBufferInfo {
232 self.fallible_build().expect("invalid command buffer info")
233 }
234}