Skip to main content

rotex_vulkan/backend/vulkan/
command.rs

1use 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}