plate/command.rs
1use std::sync::Arc;
2
3use ash::vk;
4
5use crate::{Device, Error};
6
7pub use vk::CommandBufferLevel as CommandBufferLevel;
8pub use vk::CommandBufferUsageFlags as CommandBufferUsageFlags;
9
10/// Holds a [`vk::CommandPool`], used to allocate [`CommandBuffers`](CommandBuffer).
11pub struct CommandPool {
12 device: Arc<Device>,
13 cmd_pool: vk::CommandPool,
14}
15
16impl std::ops::Deref for CommandPool {
17 type Target = vk::CommandPool;
18
19 fn deref(&self) -> &Self::Target {
20 &self.cmd_pool
21 }
22}
23
24impl Drop for CommandPool {
25 fn drop(&mut self) {
26 unsafe {
27 self.device.destroy_command_pool(self.cmd_pool, None);
28 }
29 }
30}
31
32impl CommandPool {
33 /// Creates a CommandPool.
34 ///
35 /// # Examples
36 ///
37 /// ```no_run
38 /// # let event_loop = winit::event_loop::EventLoop::new();
39 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
40 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
41 /// let cmd_pool = plate::CommandPool::new(&device)?;
42 /// # Ok::<(), Box<dyn std::error::Error>>(())
43 /// ```
44 pub fn new(device: &Arc<Device>) -> Result<Self, Error> {
45 let pool_info = vk::CommandPoolCreateInfo::builder()
46 .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
47 .queue_family_index(device.queue.family);
48
49 let cmd_pool = unsafe { device.create_command_pool(&pool_info, None)? };
50
51 Ok(Self {
52 device: Arc::clone(&device),
53 cmd_pool,
54 })
55 }
56
57 /// Allocates CommandBuffers.
58 ///
59 /// # Examples
60 ///
61 /// ```no_run
62 /// # let event_loop = winit::event_loop::EventLoop::new();
63 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
64 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
65 /// # let cmd_pool = plate::CommandPool::new(&device)?;
66 /// let cmd_buffers = cmd_pool.alloc_cmd_buffers(plate::CommandBufferLevel::PRIMARY, 2)?;
67 /// # Ok::<(), Box<dyn std::error::Error>>(())
68 /// ```
69 pub fn alloc_cmd_buffers(&self, level: CommandBufferLevel, cmd_buffer_count: u32) -> Result<Vec<CommandBuffer>, Error> {
70 let alloc_info = vk::CommandBufferAllocateInfo::builder()
71 .command_pool(self.cmd_pool)
72 .level(level)
73 .command_buffer_count(cmd_buffer_count);
74
75 let cmd_buffers = unsafe { self.device.allocate_command_buffers(&alloc_info)? };
76 Ok(cmd_buffers.into_iter()
77 .map(|cmd_buffer| CommandBuffer { device: Arc::clone(&self.device), cmd_buffer })
78 .collect())
79 }
80
81 /// Allocates a single CommandBuffer.
82 ///
83 /// # Examples
84 ///
85 /// ```no_run
86 /// # let event_loop = winit::event_loop::EventLoop::new();
87 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
88 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
89 /// # let cmd_pool = plate::CommandPool::new(&device)?;
90 /// let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
91 /// # Ok::<(), Box<dyn std::error::Error>>(())
92 /// ```
93 pub fn alloc_cmd_buffer(&self, level: CommandBufferLevel) -> Result<CommandBuffer, Error> {
94 Ok(self.alloc_cmd_buffers(level, 1)?.swap_remove(0))
95 }
96}
97
98/// Used to send instructions to the GPU.
99pub struct CommandBuffer {
100 device: Arc<Device>,
101 cmd_buffer: vk::CommandBuffer,
102}
103
104impl std::ops::Deref for CommandBuffer {
105 type Target = vk::CommandBuffer;
106
107 fn deref(&self) -> &Self::Target {
108 &self.cmd_buffer
109 }
110}
111
112impl CommandBuffer {
113 /// Records instructions in the given closure to this command buffer.
114 ///
115 /// Runs [`begin()`](Self::begin()), the closure then [`end()`](Self::end()).
116 ///
117 /// # Examples
118 ///
119 /// ```no_run
120 /// # let event_loop = winit::event_loop::EventLoop::new();
121 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
122 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
123 /// # let cmd_pool = plate::CommandPool::new(&device)?;
124 /// # let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
125 /// cmd_buffer.record(plate::CommandBufferUsageFlags::empty(), || {
126 /// // cmd_buffer.draw(..);
127 /// })?;
128 /// # Ok::<(), Box<dyn std::error::Error>>(())
129 /// ```
130 pub fn record<F: FnOnce()>(&self, flags: CommandBufferUsageFlags, f: F) -> Result<(), Error> {
131 self.begin(flags)?;
132 f();
133 self.end()?;
134 Ok(())
135 }
136
137 /// Begin recording instructions to this command buffer.
138 ///
139 /// # Examples
140 ///
141 /// ```no_run
142 /// # let event_loop = winit::event_loop::EventLoop::new();
143 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
144 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
145 /// # let cmd_pool = plate::CommandPool::new(&device)?;
146 /// # let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
147 /// cmd_buffer.begin(plate::CommandBufferUsageFlags::empty())?;
148 /// // cmd_buffer.draw(..);
149 /// # Ok::<(), Box<dyn std::error::Error>>(())
150 /// ```
151 pub fn begin(&self, flags: CommandBufferUsageFlags) -> Result<(), Error> {
152 let info = vk::CommandBufferBeginInfo::builder().flags(flags);
153 unsafe {
154 self.device.reset_command_buffer(self.cmd_buffer, vk::CommandBufferResetFlags::empty())?;
155 self.device.begin_command_buffer(self.cmd_buffer, &info)?;
156 }
157 Ok(())
158 }
159
160 /// Stop recording instructions to this command buffer.
161 ///
162 /// # Examples
163 ///
164 /// ```no_run
165 /// # let event_loop = winit::event_loop::EventLoop::new();
166 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
167 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
168 /// # let cmd_pool = plate::CommandPool::new(&device)?;
169 /// # let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
170 /// // cmd_buffer.draw(..);
171 /// cmd_buffer.end()?;
172 /// # Ok::<(), Box<dyn std::error::Error>>(())
173 /// ```
174 pub fn end(&self) -> Result<(), Error> {
175 unsafe { self.device.end_command_buffer(self.cmd_buffer)? };
176 Ok(())
177 }
178
179 /// Calls a [`draw`](ash::Device::cmd_draw()) command.
180 ///
181 /// To be used when recording a CommandBuffer.
182 ///
183 /// # Examples
184 ///
185 /// ```no_run
186 /// # let event_loop = winit::event_loop::EventLoop::new();
187 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
188 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
189 /// # let cmd_pool = plate::CommandPool::new(&device)?;
190 /// # let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
191 /// cmd_buffer.record(plate::CommandBufferUsageFlags::empty(), || {
192 /// cmd_buffer.draw(3, 1, 0, 0);
193 /// })?;
194 /// # Ok::<(), Box<dyn std::error::Error>>(())
195 /// ```
196 pub fn draw(&self, vert_count: u32, instance_count: u32, first_vert: u32, first_instance: u32) {
197 unsafe { self.device.cmd_draw(self.cmd_buffer, vert_count, instance_count, first_vert, first_instance) }
198 }
199
200 /// Calls a [`draw_indexed`](ash::Device::cmd_draw_indexed()) command.
201 ///
202 /// To be used when recording a CommandBuffer.
203 ///
204 /// # Examples
205 ///
206 /// ```no_run
207 /// # let event_loop = winit::event_loop::EventLoop::new();
208 /// # let window = winit::window::WindowBuilder::new().build(&event_loop)?;
209 /// # let device = plate::Device::new(&Default::default(), &Default::default(), Some(&window))?;
210 /// # let cmd_pool = plate::CommandPool::new(&device)?;
211 /// # let cmd_buffer = cmd_pool.alloc_cmd_buffer(plate::CommandBufferLevel::PRIMARY)?;
212 /// cmd_buffer.record(plate::CommandBufferUsageFlags::empty(), || {
213 /// cmd_buffer.draw_indexed(3, 1, 0, 0, 0);
214 /// })?;
215 /// # Ok::<(), Box<dyn std::error::Error>>(())
216 /// ```
217 pub fn draw_indexed(&self, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) {
218 unsafe { self.device.cmd_draw_indexed(self.cmd_buffer, index_count, instance_count, first_index, vertex_offset, first_instance) }
219 }
220}