Skip to main content

ursus_core/render/gfx/
encoder.rs

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}