1use super::pipeline_cache::PipelineCache;
2use crate::assets::storage::mesh::GpuMesh;
3use crate::assets::storage::GpuAssetServer;
4use crate::render::gfx::types::handles::{PipelineId, ShaderStage};
5use crate::render::gfx::types::DescriptorSetId;
6use crate::render::resource::{ImageRef, ResourceHandle, ResourcePool};
7use crate::vulkan::core::debug::{cmd_begin_label, cmd_end_label};
8use crate::vulkan::gfx_pipeline::builder::cmd::{
9 begin_rendering_clear, begin_rendering_depth_only, begin_rendering_discard, begin_rendering_load,
10};
11use ash::vk;
12
13pub struct CommandEncoder<'a> {
14 device: &'a ash::Device,
15 cmd: vk::CommandBuffer,
16 pool: &'a ResourcePool,
17 pipelines: &'a PipelineCache,
18 gpu_assets: &'a GpuAssetServer,
19 bound_pipeline: Option<PipelineId>,
20}
21
22impl<'a> CommandEncoder<'a> {
23 pub(crate) fn new(
24 device: &'a ash::Device,
25 cmd: vk::CommandBuffer,
26 pool: &'a ResourcePool,
27 pipelines: &'a PipelineCache,
28 gpu_assets: &'a GpuAssetServer,
29 ) -> Self {
30 Self { device, cmd, pool, pipelines, gpu_assets, bound_pipeline: None }
31 }
32
33 pub fn raw_cmd(&self) -> vk::CommandBuffer {
34 self.cmd
35 }
36
37 fn image(&self, handle: ResourceHandle) -> ImageRef<'_> {
38 self.pool.image(handle)
39 }
40
41 pub fn begin_rendering_depth_only(&self, depth: ResourceHandle) {
42 let img = self.image(depth);
43 begin_rendering_depth_only(self.device, self.cmd, img.view, img.extent);
44 }
45
46 pub fn begin_rendering_discard(&self, color: ResourceHandle) {
47 let img = self.image(color);
48 begin_rendering_discard(self.device, self.cmd, img.view, img.extent);
49 }
50
51 pub fn begin_rendering_load(&self, color: ResourceHandle) {
52 let img = self.image(color);
53 begin_rendering_load(self.device, self.cmd, img.view, img.extent);
54 }
55
56 pub fn begin_rendering_clear(&self, color: ResourceHandle, clear: [f32; 4]) {
57 let img = self.image(color);
58 begin_rendering_clear(self.device, self.cmd, img.view, img.extent, clear);
59 }
60
61 pub fn begin_rendering_gbuffer(
62 &self,
63 albedo: ResourceHandle,
64 normal: ResourceHandle,
65 depth: ResourceHandle,
66 clear_color: [f32; 4],
67 ) {
68 let albedo_img = self.image(albedo);
69 let normal_img = self.image(normal);
70 let depth_img = self.image(depth);
71 crate::vulkan::gfx_pipeline::builder::cmd::begin_rendering_with_depth(
72 self.device,
73 self.cmd,
74 &[(albedo_img.view, clear_color), (normal_img.view, [0.0; 4])],
75 depth_img.view,
76 vk::AttachmentLoadOp::LOAD,
77 albedo_img.extent,
78 );
79 }
80
81 pub fn blit_to_swapchain(&self, src: ResourceHandle, dst: ResourceHandle) {
82 let src_img = self.image(src);
83 let dst_img = self.image(dst);
84 let blit = vk::ImageBlit2::default()
85 .src_subresource(vk::ImageSubresourceLayers {
86 aspect_mask: vk::ImageAspectFlags::COLOR,
87 mip_level: 0,
88 base_array_layer: 0,
89 layer_count: 1,
90 })
91 .src_offsets([
92 vk::Offset3D::default(),
93 vk::Offset3D { x: src_img.extent.width as i32, y: src_img.extent.height as i32, z: 1 },
94 ])
95 .dst_subresource(vk::ImageSubresourceLayers {
96 aspect_mask: vk::ImageAspectFlags::COLOR,
97 mip_level: 0,
98 base_array_layer: 0,
99 layer_count: 1,
100 })
101 .dst_offsets([
102 vk::Offset3D::default(),
103 vk::Offset3D { x: dst_img.extent.width as i32, y: dst_img.extent.height as i32, z: 1 },
104 ]);
105
106 unsafe {
107 self.device.cmd_blit_image2(
108 self.cmd,
109 &vk::BlitImageInfo2::default()
110 .src_image(src_img.image)
111 .src_image_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
112 .dst_image(dst_img.image)
113 .dst_image_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
114 .regions(std::slice::from_ref(&blit))
115 .filter(vk::Filter::LINEAR),
116 );
117 }
118 }
119
120 pub fn end_rendering(&self) {
121 unsafe { self.device.cmd_end_rendering(self.cmd) };
122 }
123
124 pub fn bind_pipeline(&mut self, pipeline: PipelineId) {
125 let stored = self.pipelines.get(pipeline);
126 unsafe { self.device.cmd_bind_pipeline(self.cmd, vk::PipelineBindPoint::GRAPHICS, stored.handle) };
127 self.bound_pipeline = Some(pipeline);
128 }
129
130 pub fn bind_descriptor_sets(&self, pipeline: PipelineId, sets: &[DescriptorSetId]) {
131 let stored = self.pipelines.get(pipeline);
132 let vk_sets: Vec<vk::DescriptorSet> = sets.iter().map(|&id| self.gpu_assets.descriptors.handle(id)).collect();
133
134 unsafe {
135 self.device.cmd_bind_descriptor_sets(
136 self.cmd,
137 vk::PipelineBindPoint::GRAPHICS,
138 stored.layout,
139 0,
140 &vk_sets,
141 &[],
142 );
143 }
144 }
145
146 pub fn push_constants<T: bytemuck::Pod>(&self, pipeline: PipelineId, stage: ShaderStage, data: &T) {
147 let stored = self.pipelines.get(pipeline);
148 let bytes = bytemuck::bytes_of(data);
149 unsafe { self.device.cmd_push_constants(self.cmd, stored.layout, stage.to_vk(), 0, bytes) };
150 }
151
152 pub fn bind_mesh(&self, mesh: &GpuMesh) {
153 unsafe {
154 self.device.cmd_bind_vertex_buffers(self.cmd, 0, &[mesh.vertex_buffer], &[0]);
155 self.device.cmd_bind_index_buffer(self.cmd, mesh.index_buffer, 0, vk::IndexType::UINT32);
156 }
157 }
158
159 pub fn draw_indexed(&self, index_count: u32) {
160 unsafe { self.device.cmd_draw_indexed(self.cmd, index_count, 1, 0, 0, 0) };
161 }
162
163 pub fn draw(&self, vertex_count: u32) {
164 unsafe { self.device.cmd_draw(self.cmd, vertex_count, 1, 0, 0) };
165 }
166
167 pub fn set_debug_label(&self, debug_utils: Option<&ash::ext::debug_utils::Device>, name: &str) {
168 if let Some(du) = debug_utils {
169 cmd_begin_label(du, self.cmd, name);
170 }
171 }
172
173 pub fn end_debug_label(&self, debug_utils: Option<&ash::ext::debug_utils::Device>) {
174 if let Some(du) = debug_utils {
175 cmd_end_label(du, self.cmd);
176 }
177 }
178
179 pub fn extent_of(&self, handle: ResourceHandle) -> [f32; 2] {
180 let img = self.image(handle);
181 [img.extent.width as f32, img.extent.height as f32]
182 }
183}