vulkayes_core/command/buffer/
mod.rs

1use std::{fmt::Debug, ops::Deref};
2
3use ash::{version::DeviceV1_0, vk};
4
5use crate::{
6	command::pool::CommandPool,
7	prelude::{HasSynchronizedHandle, Vrc},
8	util::sync::Vutex
9};
10
11use super::error::CommandBufferError;
12
13pub mod recording;
14// pub mod clear;
15// pub mod control;
16// pub mod render_pass;
17// pub mod bind;
18
19pub struct CommandBuffer {
20	pool: Vrc<CommandPool>,
21	command_buffer: Vutex<vk::CommandBuffer>
22}
23impl CommandBuffer {
24	pub fn new(pool: Vrc<CommandPool>, primary: bool) -> Result<Vrc<Self>, CommandBufferError> {
25		let level = match primary {
26			true => vk::CommandBufferLevel::PRIMARY,
27			false => vk::CommandBufferLevel::SECONDARY
28		};
29		let [raw] = unsafe { pool.allocate_command_buffer(level)? };
30
31		Ok(Vrc::new(unsafe { Self::from_existing(pool, raw) }))
32	}
33
34	pub fn new_multiple(
35		pool: Vrc<CommandPool>,
36		primary: bool,
37		count: std::num::NonZeroU32
38	) -> Result<Vec<Vrc<Self>>, CommandBufferError> {
39		let level = match primary {
40			true => vk::CommandBufferLevel::PRIMARY,
41			false => vk::CommandBufferLevel::SECONDARY
42		};
43		let raw = unsafe { pool.allocate_command_buffers(level, count)? };
44
45		let buffers: Vec<_> = raw
46			.into_iter()
47			.map(|command_buffer| {
48				Vrc::new(unsafe { Self::from_existing(pool.clone(), command_buffer) })
49			})
50			.collect();
51
52		Ok(buffers)
53	}
54
55	/// Creates a new `CommandBuffer` from existing handle.
56	///
57	/// ### Safety
58	///
59	/// `command_buffer` must be valid handle allocated from `pool`.
60	pub unsafe fn from_existing(pool: Vrc<CommandPool>, command_buffer: vk::CommandBuffer) -> Self {
61		log_trace_common!(
62			"Creating CommandBuffer from existing handle:",
63			pool,
64			crate::util::fmt::format_handle(command_buffer)
65		);
66
67		Self {
68			pool,
69			command_buffer: Vutex::new(command_buffer)
70		}
71	}
72
73	/// ### Panic
74	///
75	/// This function will panic if the vutex cannot be locked.
76	pub fn reset(&self, release_resource: bool) -> Result<(), CommandBufferError> {
77		let handle = self.lock_handle();
78
79		let flags = if release_resource {
80			vk::CommandBufferResetFlags::RELEASE_RESOURCES
81		} else {
82			vk::CommandBufferResetFlags::empty()
83		};
84
85		log_trace_common!(
86			"Resetting command buffer:",
87			crate::util::fmt::format_handle(*handle),
88			flags
89		);
90		unsafe {
91			self.pool()
92				.device()
93				.reset_command_buffer(*handle, flags)
94				.map_err(CommandBufferError::from)
95		}
96	}
97
98	/// Equivalent to calling `CommandBufferRecordingLock::new(self)`
99	///
100	/// ### Panic
101	///
102	/// This function will panic if the pool or the buffer vutex cannot be locked.
103	pub fn begin_recording(
104		&self,
105		info: recording::CommandBufferBeginInfo
106	) -> Result<recording::CommandBufferRecordingLockOutsideRenderPass, CommandBufferError> {
107		let lock = recording::common::CommandBufferRecordingLockCommon::new(self);
108
109		recording::CommandBufferRecordingLockOutsideRenderPass::new(lock, info)
110	}
111
112	pub const fn pool(&self) -> &Vrc<CommandPool> {
113		&self.pool
114	}
115}
116impl_common_handle_traits! {
117	impl HasSynchronizedHandle<vk::CommandBuffer>, Deref, Borrow, Eq, Hash, Ord for CommandBuffer {
118		target = { command_buffer }
119	}
120}
121impl Drop for CommandBuffer {
122	fn drop(&mut self) {
123		let lock = self.command_buffer.lock().expect("vutex poisoned");
124		log_trace_common!("Dropping", self, lock);
125
126		unsafe { self.pool.free_command_buffers([*lock]) }
127	}
128}
129impl Debug for CommandBuffer {
130	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
131		f.debug_struct("CommandBuffer")
132			.field("pool", &self.pool)
133			.field("command_buffer", &self.command_buffer)
134			.finish()
135	}
136}