1use crate::{
2 Buffer, CommandPool, DescriptorSet, Device, DeviceOwned, ImageAccess, PipelineAccess,
3 PipelineLayout,
4};
5use ash::{
6 prelude::VkResult,
7 vk::{self, Handle},
8};
9use std::{error::Error, sync::Arc};
10
11pub struct CommandBuffer {
12 handle: vk::CommandBuffer,
13 level: vk::CommandBufferLevel,
14
15 command_pool: Arc<CommandPool>,
17}
18
19impl CommandBuffer {
20 pub fn new(command_pool: Arc<CommandPool>, level: vk::CommandBufferLevel) -> VkResult<Self> {
22 let mut command_buffers = command_pool.allocate_command_buffers(level, 1)?;
23 Ok(command_buffers.remove(0))
24 }
25
26 pub(crate) unsafe fn from_handle(
28 handle: vk::CommandBuffer,
29 level: vk::CommandBufferLevel,
30 command_pool: Arc<CommandPool>,
31 ) -> Self {
32 Self {
33 handle,
34 level,
35 command_pool,
36 }
37 }
38
39 pub fn reset(&self, reset_flags: vk::CommandBufferResetFlags) -> VkResult<()> {
44 unsafe {
45 self.device()
46 .inner()
47 .reset_command_buffer(self.handle, reset_flags)
48 }
49 }
50
51 pub fn handle(&self) -> vk::CommandBuffer {
54 self.handle
55 }
56
57 pub fn level(&self) -> vk::CommandBufferLevel {
58 self.level
59 }
60
61 #[inline]
62 pub fn command_pool(&self) -> &Arc<CommandPool> {
63 &self.command_pool
64 }
65
66 pub fn begin(&self, begin_info: &vk::CommandBufferBeginInfoBuilder) -> VkResult<()> {
70 unsafe {
71 self.device()
72 .inner()
73 .begin_command_buffer(self.handle, begin_info)
74 }
75 }
76
77 pub fn end(&self) -> VkResult<()> {
79 unsafe { self.device().inner().end_command_buffer(self.handle) }
80 }
81
82 pub fn begin_render_pass(
84 &self,
85 begin_info: &vk::RenderPassBeginInfoBuilder,
86 subpass_contents: vk::SubpassContents,
87 ) {
88 unsafe {
89 self.device()
90 .inner()
91 .cmd_begin_render_pass(self.handle, &begin_info, subpass_contents)
92 }
93 }
94
95 pub fn next_subpass(&self, subpass_contents: vk::SubpassContents) {
97 unsafe {
98 self.device()
99 .inner()
100 .cmd_next_subpass(self.handle, subpass_contents)
101 }
102 }
103
104 pub fn end_render_pass(&self) {
106 unsafe { self.device().inner().cmd_end_render_pass(self.handle) }
107 }
108
109 pub fn bind_pipeline(&self, pipeline: &dyn PipelineAccess) {
111 unsafe {
112 self.device().inner().cmd_bind_pipeline(
113 self.handle,
114 pipeline.bind_point(),
115 pipeline.handle(),
116 )
117 }
118 }
119
120 pub fn bind_descriptor_sets<'a>(
122 &self,
123 pipeline_bind_point: vk::PipelineBindPoint,
124 pipeline_layout: &PipelineLayout,
125 first_set: u32,
126 descriptor_sets: impl IntoIterator<Item = &'a DescriptorSet>,
127 dynamic_offsets: &[u32],
128 ) {
129 let descriptor_set_handles: Vec<vk::DescriptorSet> = descriptor_sets
130 .into_iter()
131 .map(|descriptor_set| descriptor_set.handle())
132 .collect();
133 unsafe {
134 self.device().inner().cmd_bind_descriptor_sets(
135 self.handle,
136 pipeline_bind_point,
137 pipeline_layout.handle(),
138 first_set,
139 &descriptor_set_handles,
140 dynamic_offsets,
141 )
142 }
143 }
144
145 pub fn bind_vertex_buffers<'a>(
147 &self,
148 first_binding: u32,
149 buffers: impl IntoIterator<Item = &'a Buffer>,
150 offsets: &[vk::DeviceSize],
151 ) {
152 let buffer_handles: Vec<vk::Buffer> =
153 buffers.into_iter().map(|buffer| buffer.handle()).collect();
154 unsafe {
155 self.device().inner().cmd_bind_vertex_buffers(
156 self.handle,
157 first_binding,
158 &buffer_handles,
159 offsets,
160 )
161 }
162 }
163
164 pub fn bind_index_buffer(
166 &self,
167 buffer: &Buffer,
168 offset: vk::DeviceSize,
169 index_type: vk::IndexType,
170 ) {
171 unsafe {
172 self.device().inner().cmd_bind_index_buffer(
173 self.handle,
174 buffer.handle(),
175 offset,
176 index_type,
177 )
178 }
179 }
180
181 pub fn set_viewport(&self, first_viewport: u32, viewports: &[vk::Viewport]) {
183 unsafe {
184 self.device()
185 .inner()
186 .cmd_set_viewport(self.handle, first_viewport, viewports)
187 }
188 }
189
190 pub fn set_scissor(&self, first_scissor: u32, scissors: &[vk::Rect2D]) {
192 unsafe {
193 self.device()
194 .inner()
195 .cmd_set_scissor(self.handle, first_scissor, scissors)
196 }
197 }
198
199 pub fn draw(
201 &self,
202 vertex_count: u32,
203 instance_count: u32,
204 first_vertex: u32,
205 first_instance: u32,
206 ) {
207 unsafe {
208 self.device().inner().cmd_draw(
209 self.handle,
210 vertex_count,
211 instance_count,
212 first_vertex,
213 first_instance,
214 )
215 }
216 }
217
218 pub fn draw_indexed(
220 &self,
221 index_count: u32,
222 instance_count: u32,
223 first_index: u32,
224 vertex_offset: i32,
225 first_instance: u32,
226 ) {
227 unsafe {
228 self.device().inner().cmd_draw_indexed(
229 self.handle,
230 index_count,
231 instance_count,
232 first_index,
233 vertex_offset,
234 first_instance,
235 )
236 }
237 }
238
239 pub fn draw_indexed_indirect(
241 &self,
242 buffer: &Buffer,
243 offset: vk::DeviceSize,
244 draw_count: u32,
245 stride: u32,
246 ) {
247 unsafe {
248 self.device().inner().cmd_draw_indexed_indirect(
249 self.handle,
250 buffer.handle(),
251 offset,
252 draw_count,
253 stride,
254 )
255 }
256 }
257
258 pub fn execute_commands(
260 &self,
261 secondary_command_buffers: &[&CommandBuffer],
262 ) -> Result<(), CommandError> {
263 let any_primary_buffers = secondary_command_buffers
264 .iter()
265 .any(|command_buffer| command_buffer.level == vk::CommandBufferLevel::PRIMARY);
266 if any_primary_buffers {
267 return Err(CommandError::CantExecutePrimaryCommandBuffer);
268 }
269
270 let secondary_command_buffer_handles: Vec<vk::CommandBuffer> = secondary_command_buffers
271 .iter()
272 .map(|command_buffer| command_buffer.handle())
273 .collect();
274
275 unsafe {
276 self.device()
277 .inner()
278 .cmd_execute_commands(self.handle, &secondary_command_buffer_handles);
279 }
280
281 Ok(())
282 }
283
284 pub fn copy_buffer(
286 &self,
287 src_buffer: &Buffer,
288 dst_buffer: &Buffer,
289 regions: &[vk::BufferCopy],
290 ) {
291 unsafe {
292 self.device().inner().cmd_copy_buffer(
293 self.handle,
294 src_buffer.handle(),
295 dst_buffer.handle(),
296 regions,
297 )
298 }
299 }
300
301 pub fn copy_buffer_to_image(
303 &self,
304 src_buffer: &Buffer,
305 dst_image: &dyn ImageAccess,
306 dst_image_layout: vk::ImageLayout,
307 regions: &[vk::BufferImageCopy],
308 ) {
309 unsafe {
310 self.device().inner().cmd_copy_buffer_to_image(
311 self.handle,
312 src_buffer.handle(),
313 dst_image.handle(),
314 dst_image_layout,
315 regions,
316 )
317 }
318 }
319
320 pub fn push_constants(
322 &self,
323 pipeline_layout: &PipelineLayout,
324 stage_flags: vk::ShaderStageFlags,
325 offset: u32,
326 constants: &[u8],
327 ) {
328 unsafe {
329 self.device().inner().cmd_push_constants(
330 self.handle,
331 pipeline_layout.handle(),
332 stage_flags,
333 offset,
334 constants,
335 )
336 }
337 }
338}
339
340impl Drop for CommandBuffer {
341 fn drop(&mut self) {
342 unsafe {
343 self.device()
344 .inner()
345 .free_command_buffers(self.command_pool.handle(), &[self.handle])
346 }
347 }
348}
349
350impl DeviceOwned for CommandBuffer {
351 #[inline]
352 fn device(&self) -> &Arc<Device> {
353 self.command_pool.device()
354 }
355
356 #[inline]
357 fn handle_raw(&self) -> u64 {
358 self.handle.as_raw()
359 }
360}
361
362#[derive(Clone, Copy, Debug)]
365pub enum CommandError {
366 CantExecutePrimaryCommandBuffer,
367}
368
369impl std::fmt::Display for CommandError {
370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371 match self {
372 Self::CantExecutePrimaryCommandBuffer => write!(
373 f,
374 "attempted to call vkCmdExecuteCommands on a primary command buffer"
375 ),
376 }
377 }
378}
379
380impl Error for CommandError {}