rotex_vulkan/backend/vulkan/
command.rs1use ash::vk;
2
3use super::buffer::RotexBuffer;
4use super::device::{Device, QueueCategory};
5use super::framebuffer::Framebuffer;
6use super::pass::RenderPass;
7use crate::error::{Error, ErrorKind, Severity, vk_error};
8
9pub struct CommandBuffer {
10 pub(crate) handle: vk::CommandBuffer,
11}
12
13impl CommandBuffer {
14 pub fn handle(&self) -> vk::CommandBuffer {
15 self.handle
16 }
17
18 pub fn begin(&self, device: &Device, flags: vk::CommandBufferUsageFlags) -> Result<(), Error> {
19 let begin_info = vk::CommandBufferBeginInfo::default().flags(flags);
20
21 unsafe {
22 device
23 .logical_device()
24 .begin_command_buffer(self.handle, &begin_info)
25 }
26 .map_err(vk_error)
27 }
28
29 pub fn begin_render_pass(
30 &self,
31 device: &Device,
32 render_pass: &RenderPass,
33 framebuffer: &Framebuffer,
34 clear_values: &[vk::ClearValue],
35 ) {
36 debug_assert_eq!(
37 clear_values.len() as u32,
38 render_pass.attachments().len() as u32,
39 "Rotex Core Panic: The number of clear values does not match the Render Pass attachment count!"
40 );
41
42 let render_pass_info = vk::RenderPassBeginInfo::default()
43 .render_pass(render_pass.handle())
44 .framebuffer(framebuffer.handle())
45 .render_area(vk::Rect2D {
46 offset: vk::Offset2D { x: 0, y: 0 },
47 extent: framebuffer.extent(),
48 })
49 .clear_values(clear_values);
50
51 unsafe {
52 device.logical_device().cmd_begin_render_pass(
53 self.handle,
54 &render_pass_info,
55 vk::SubpassContents::INLINE,
56 );
57 }
58 }
59
60 pub fn end_render_pass(&self, device: &Device) {
61 unsafe {
62 device.logical_device().cmd_end_render_pass(self.handle);
63 }
64 }
65
66 pub fn end(&self, device: &Device) -> Result<(), Error> {
67 unsafe { device.logical_device().end_command_buffer(self.handle) }.map_err(vk_error)
68 }
69
70 pub fn bind_graphics_pipeline(&self, device: &Device, pipeline: vk::Pipeline) {
71 unsafe {
72 device.logical_device().cmd_bind_pipeline(
73 self.handle,
74 vk::PipelineBindPoint::GRAPHICS,
75 pipeline,
76 );
77 }
78 }
79
80 pub fn bind_graphics_descriptor_sets(
81 &self,
82 device: &Device,
83 pipeline_layout: vk::PipelineLayout,
84 first_set: u32,
85 descriptor_sets: &[vk::DescriptorSet],
86 ) {
87 unsafe {
88 device.logical_device().cmd_bind_descriptor_sets(
89 self.handle,
90 vk::PipelineBindPoint::GRAPHICS,
91 pipeline_layout,
92 first_set,
93 descriptor_sets,
94 &[],
95 );
96 }
97 }
98
99 pub fn bind_vertex_buffer(&self, device: &Device, buffer: vk::Buffer) {
100 unsafe {
101 device
102 .logical_device()
103 .cmd_bind_vertex_buffers(self.handle, 0, &[buffer], &[0]);
104 }
105 }
106
107 pub fn draw(&self, device: &Device, vertex_count: u32) {
108 unsafe {
109 device
110 .logical_device()
111 .cmd_draw(self.handle, vertex_count, 1, 0, 0);
112 }
113 }
114
115 pub fn set_viewport(&self, device: &Device, viewport: vk::Viewport) {
116 unsafe {
117 device
118 .logical_device()
119 .cmd_set_viewport(self.handle, 0, &[viewport]);
120 }
121 }
122
123 pub fn set_scissor(&self, device: &Device, scissor: vk::Rect2D) {
124 unsafe {
125 device
126 .logical_device()
127 .cmd_set_scissor(self.handle, 0, &[scissor]);
128 }
129 }
130
131 pub fn transition_image_layout(
132 &self,
133 device: &Device,
134 image: vk::Image,
135 old_layout: vk::ImageLayout,
136 new_layout: vk::ImageLayout,
137 aspect_mask: vk::ImageAspectFlags,
138 ) {
139 let (src_access, src_stage) = Self::infer_state(old_layout);
140 let (dst_access, dst_stage) = Self::infer_state(new_layout);
141
142 let barrier = vk::ImageMemoryBarrier::default()
143 .old_layout(old_layout)
144 .new_layout(new_layout)
145 .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
146 .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
147 .image(image)
148 .subresource_range(vk::ImageSubresourceRange {
149 aspect_mask,
150 base_mip_level: 0,
151 level_count: 1,
152 base_array_layer: 0,
153 layer_count: 1,
154 })
155 .src_access_mask(src_access)
156 .dst_access_mask(dst_access);
157
158 unsafe {
159 device.logical_device().cmd_pipeline_barrier(
160 self.handle,
161 src_stage,
162 dst_stage,
163 vk::DependencyFlags::empty(),
164 &[],
165 &[],
166 &[barrier],
167 );
168 }
169 }
170
171 pub fn copy_buffer_to_image(
172 &self,
173 device: &Device,
174 buffer: vk::Buffer,
175 image: vk::Image,
176 width: u32,
177 height: u32,
178 ) {
179 let region = vk::BufferImageCopy::default()
180 .buffer_offset(0)
181 .buffer_row_length(0)
182 .buffer_image_height(0)
183 .image_subresource(
184 vk::ImageSubresourceLayers::default()
185 .aspect_mask(vk::ImageAspectFlags::COLOR)
186 .mip_level(0)
187 .base_array_layer(0)
188 .layer_count(1),
189 )
190 .image_offset(vk::Offset3D { x: 0, y: 0, z: 0 })
191 .image_extent(vk::Extent3D {
192 width,
193 height,
194 depth: 1,
195 });
196 unsafe {
197 device.logical_device().cmd_copy_buffer_to_image(
198 self.handle,
199 buffer,
200 image,
201 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
202 &[region],
203 );
204 }
205 }
206
207 fn infer_state(layout: vk::ImageLayout) -> (vk::AccessFlags, vk::PipelineStageFlags) {
208 match layout {
209 vk::ImageLayout::UNDEFINED => (
210 vk::AccessFlags::empty(),
211 vk::PipelineStageFlags::TOP_OF_PIPE,
212 ),
213 vk::ImageLayout::TRANSFER_DST_OPTIMAL => (
214 vk::AccessFlags::TRANSFER_WRITE,
215 vk::PipelineStageFlags::TRANSFER,
216 ),
217 vk::ImageLayout::TRANSFER_SRC_OPTIMAL => (
218 vk::AccessFlags::TRANSFER_READ,
219 vk::PipelineStageFlags::TRANSFER,
220 ),
221 vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL => (
222 vk::AccessFlags::SHADER_READ,
223 vk::PipelineStageFlags::FRAGMENT_SHADER,
224 ),
225 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL => (
226 vk::AccessFlags::COLOR_ATTACHMENT_WRITE | vk::AccessFlags::COLOR_ATTACHMENT_READ,
227 vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
228 ),
229 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL => (
230 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
231 | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
232 vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
233 | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS,
234 ),
235 _ => {
236 panic!("Rotex Core Panic: Layout transition rule not defined in state inferencer!")
237 }
238 }
239 }
240
241 pub fn bind_index_buffer(
242 &self,
243 device: &Device,
244 buffer: &RotexBuffer,
245 offset: vk::DeviceSize,
246 index_type: vk::IndexType,
247 ) {
248 unsafe {
249 device.logical_device().cmd_bind_index_buffer(
250 self.handle,
251 buffer.handle(),
252 offset,
253 index_type,
254 );
255 }
256 }
257
258 pub fn draw_indexed(
259 &self,
260 device: &Device,
261 index_count: u32,
262 instance_count: u32,
263 first_index: u32,
264 vertex_offset: i32,
265 first_instance: u32,
266 ) {
267 unsafe {
268 device.logical_device().cmd_draw_indexed(
269 self.handle,
270 index_count,
271 instance_count,
272 first_index,
273 vertex_offset,
274 first_instance,
275 );
276 }
277 }
278}
279
280pub struct CommandPool {
281 pub(crate) handle: vk::CommandPool,
282}
283
284impl CommandPool {
285 pub fn new(device: &Device) -> Result<Self, Error> {
286 let graphics_queue = device
287 .queues()
288 .iter()
289 .find(|q| q.category == QueueCategory::Graphics)
290 .ok_or(Error {
291 kind: ErrorKind::NoCompatibleDevice,
292 severity: Severity::Fatal,
293 })?;
294
295 let pool_info = vk::CommandPoolCreateInfo::default()
296 .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
297 .queue_family_index(graphics_queue.family_index);
298
299 let handle = unsafe { device.logical_device().create_command_pool(&pool_info, None) }
300 .map_err(vk_error)?;
301
302 Ok(Self { handle })
303 }
304
305 pub fn allocate_buffers(
306 &self,
307 device: &Device,
308 count: u32,
309 ) -> Result<Vec<CommandBuffer>, Error> {
310 let alloc_info = vk::CommandBufferAllocateInfo::default()
311 .command_pool(self.handle)
312 .level(vk::CommandBufferLevel::PRIMARY)
313 .command_buffer_count(count);
314
315 let handles = unsafe { device.logical_device().allocate_command_buffers(&alloc_info) }
316 .map_err(vk_error)?;
317
318 Ok(handles
319 .into_iter()
320 .map(|handle| CommandBuffer { handle })
321 .collect())
322 }
323
324 pub fn destroy(&self, device: &Device) {
325 unsafe {
326 device.logical_device().destroy_command_pool(self.handle, None);
327 }
328 }
329}