1mod dynamic_buffer;
5mod frame_constants;
6mod material;
7mod mesh;
8mod texture;
9pub(crate) mod utility;
10
11use {
12 self::frame_constants::FrameConstants,
13 crate::graphics::vulkan::{
14 raii, spirv_words, Frame, FramesInFlight, VulkanContext,
15 },
16 anyhow::{Context, Result},
17 ash::vk,
18 dynamic_buffer::DynamicBuffer,
19 material::Material,
20 std::sync::Arc,
21};
22
23pub use self::{
24 mesh::{Mesh, TrianglesMesh, Vertex},
25 texture::{Texture, TextureAtlas, TextureLoader},
26};
27
28const INITIAL_CAPACITY: usize = 4096;
29
30#[derive(Debug, Clone)]
31struct DrawParams {
32 index_offset: u32,
33 vertex_offset: u32,
34 index_count: u32,
35 material: Arc<Material>,
36 transform_index: u32,
37 scissor: vk::Rect2D,
38}
39
40#[repr(C, align(16))]
41#[derive(Debug, Copy, Clone)]
42struct MeshTransform {
43 matrix: [[f32; 4]; 4],
44}
45
46struct FrameDraw {
51 vertex_buffer: DynamicBuffer<Vertex>,
52 index_buffer: DynamicBuffer<u32>,
53 transforms: DynamicBuffer<MeshTransform>,
54 draw_params: Vec<DrawParams>,
55}
56
57impl FrameDraw {
58 pub fn new(ctx: &VulkanContext) -> Result<Self> {
59 Ok(Self {
60 vertex_buffer: DynamicBuffer::new(
61 ctx,
62 INITIAL_CAPACITY,
63 vk::BufferUsageFlags::STORAGE_BUFFER
64 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
65 )?,
66 index_buffer: DynamicBuffer::new(
67 ctx,
68 INITIAL_CAPACITY,
69 vk::BufferUsageFlags::INDEX_BUFFER,
70 )?,
71 transforms: DynamicBuffer::new(
72 ctx,
73 INITIAL_CAPACITY,
74 vk::BufferUsageFlags::STORAGE_BUFFER
75 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
76 )?,
77 draw_params: Vec::with_capacity(4),
78 })
79 }
80}
81
82pub struct StreamingRenderer<PerFrameDataT: Copy = ()> {
84 frame_draw_resources: Vec<FrameDraw>,
85 frame_constants: FrameConstants<PerFrameDataT>,
86
87 pipeline_layout: raii::PipelineLayout,
88
89 default_vertex_shader_module: raii::ShaderModule,
90 default_fragment_shader_module: raii::ShaderModule,
91 default_material: Arc<Material>,
92 image_format: vk::Format,
93}
94
95impl<PerFrameDataT: Copy> StreamingRenderer<PerFrameDataT> {
96 pub fn new(
97 ctx: &VulkanContext,
98 image_format: vk::Format,
99 frames_in_flight: &FramesInFlight,
100 texture_atlas: &TextureAtlas,
101 ) -> Result<Self> {
102 let frame_constants = FrameConstants::new(ctx, frames_in_flight)
103 .context("Unable to create FrameData instance")?;
104
105 let pipeline_layout = Material::create_pipeline_layout(
107 ctx,
108 texture_atlas.descriptor_set_layout(),
109 frame_constants.descriptor_set_layout(),
110 )
111 .context("Unable to create pipeline layout")?;
112
113 let frame_draw_resources = {
114 let mut resources =
115 Vec::with_capacity(frames_in_flight.frame_count());
116 for frame_index in 0..frames_in_flight.frame_count() {
117 resources.push(FrameDraw::new(ctx).context(format!(
118 "Unable to create draw resources for frame {}",
119 frame_index
120 ))?);
121 }
122 resources
123 };
124
125 let default_vertex_shader_module = {
126 let vertex_shader_words =
127 spirv_words(include_bytes!("./shaders/triangle.vert.spv"))
128 .context("Unable to pack default vertex shader source")?;
129 raii::ShaderModule::new(
130 "DefaultVertexShader",
131 ctx.device.clone(),
132 &vk::ShaderModuleCreateInfo {
133 code_size: vertex_shader_words.len() * 4,
134 p_code: vertex_shader_words.as_ptr(),
135 ..Default::default()
136 },
137 )
138 .context("Unable to create default vertex shader module")?
139 };
140 let default_fragment_shader_module = {
141 let fragment_shader_words =
142 spirv_words(include_bytes!("./shaders/triangle.frag.spv"))
143 .context("Unable to pack default fragment shader source")?;
144 raii::ShaderModule::new(
145 "DefaultFragmentShader",
146 ctx.device.clone(),
147 &vk::ShaderModuleCreateInfo {
148 code_size: fragment_shader_words.len() * 4,
149 p_code: fragment_shader_words.as_ptr(),
150 ..Default::default()
151 },
152 )
153 .context("Unable to create default fragment shader module")?
154 };
155 let default_material = Arc::new(
156 Material::new(
157 ctx,
158 image_format,
159 &pipeline_layout,
160 &default_vertex_shader_module,
161 &default_fragment_shader_module,
162 )
163 .context("Unable to create default material")?,
164 );
165
166 Ok(Self {
167 frame_draw_resources,
168 frame_constants,
169
170 pipeline_layout,
171 default_vertex_shader_module,
172 default_fragment_shader_module,
173 default_material,
174 image_format,
175 })
176 }
177
178 pub fn new_material(
184 &self,
185 ctx: &VulkanContext,
186 vertex_shader: Option<&raii::ShaderModule>,
187 fragment_shader: Option<&raii::ShaderModule>,
188 ) -> Result<Arc<Material>> {
189 let material = Material::new(
190 ctx,
191 self.image_format,
192 &self.pipeline_layout,
193 vertex_shader.unwrap_or(&self.default_vertex_shader_module),
194 fragment_shader.unwrap_or(&self.default_fragment_shader_module),
195 )
196 .context("Unable to create new material!")?;
197 Ok(Arc::new(material))
198 }
199
200 pub fn image_format(&self) -> vk::Format {
202 self.image_format
203 }
204
205 pub fn default_material(&self) -> &Arc<Material> {
208 &self.default_material
209 }
210
211 pub fn prepare_meshes(
216 &mut self,
217 ctx: &VulkanContext,
218 frame: &Frame,
219 meshes: &[&dyn Mesh],
220 ) -> Result<()> {
221 let frame_draw = &mut self.frame_draw_resources[frame.frame_index()];
222 frame_draw.draw_params.clear();
223
224 let (vertex_data, index_data) = {
226 let mut vertex_data = Vec::with_capacity(meshes.len());
227 let mut index_data = Vec::with_capacity(meshes.len());
228 let mut index_offset = 0;
229 let mut vertex_offset = 0;
230
231 for (transform_index, mesh) in meshes.iter().enumerate() {
232 let vertices = mesh.vertices();
233 let indices = mesh.indices();
234 vertex_data.push(vertices);
235 index_data.push(indices);
236
237 frame_draw.draw_params.push(DrawParams {
238 index_offset,
239 vertex_offset,
240 index_count: indices.len() as u32,
241 material: mesh.material().clone(),
242 transform_index: transform_index as u32,
243 scissor: mesh.scissor(),
244 });
245
246 index_offset += indices.len() as u32;
247 vertex_offset += vertices.len() as u32;
248 }
249
250 (vertex_data, index_data)
251 };
252
253 unsafe {
255 frame_draw
256 .vertex_buffer
257 .write_chunked_data(ctx, &vertex_data)
258 .context("Unable to write frame vertex data!")?;
259 frame_draw
260 .index_buffer
261 .write_chunked_data(ctx, &index_data)
262 .context("Unable to write index data!")?;
263 frame_draw.transforms.write_iterated_data(
264 ctx,
265 meshes.iter().map(|mesh| MeshTransform {
266 matrix: mesh.transform().data.0,
267 }),
268 )?;
269 }
270
271 Ok(())
272 }
273
274 pub fn set_frame_constants(
275 &mut self,
276 frame: &Frame,
277 data: PerFrameDataT,
278 ) -> Result<()> {
279 self.frame_constants.set_data(frame, data)
280 }
281
282 pub fn bind_texture_atlas(
288 &mut self,
289 ctx: &VulkanContext,
290 frame: &Frame,
291 texture_atlas: &TextureAtlas,
292 ) {
293 unsafe {
294 ctx.cmd_bind_descriptor_sets(
295 frame.command_buffer(),
296 vk::PipelineBindPoint::GRAPHICS,
297 self.pipeline_layout.raw,
298 0,
299 &[texture_atlas.descriptor_set()],
300 &[],
301 );
302 }
303 }
304
305 pub fn write_draw_commands(
310 &mut self,
311 ctx: &VulkanContext,
312 frame: &Frame,
313 ) -> Result<()> {
314 let frame_draw = &mut self.frame_draw_resources[frame.frame_index()];
315 unsafe {
316 ctx.cmd_bind_descriptor_sets(
317 frame.command_buffer(),
318 vk::PipelineBindPoint::GRAPHICS,
319 self.pipeline_layout.raw,
320 1,
321 &[self.frame_constants.descriptor_set_for_frame(frame)],
322 &[],
323 );
324 ctx.cmd_bind_index_buffer(
325 frame.command_buffer(),
326 frame_draw.index_buffer.raw(),
327 0,
328 vk::IndexType::UINT32,
329 );
330 ctx.cmd_push_constants(
331 frame.command_buffer(),
332 self.pipeline_layout.raw,
333 vk::ShaderStageFlags::VERTEX,
334 0,
335 &frame_draw
336 .vertex_buffer
337 .buffer_device_address()
338 .to_le_bytes(),
339 );
340 ctx.cmd_push_constants(
341 frame.command_buffer(),
342 self.pipeline_layout.raw,
343 vk::ShaderStageFlags::VERTEX,
344 8,
345 &frame_draw.transforms.buffer_device_address().to_le_bytes(),
346 );
347 }
348
349 let mut last_bound_pipeline = vk::Pipeline::null();
350 for draw_params in frame_draw.draw_params.drain(0..) {
351 let pipeline = draw_params.material.pipeline().raw;
354 if pipeline != last_bound_pipeline {
355 unsafe {
356 ctx.cmd_bind_pipeline(
357 frame.command_buffer(),
358 vk::PipelineBindPoint::GRAPHICS,
359 pipeline,
360 );
361 }
362 last_bound_pipeline = pipeline;
363 }
364 unsafe {
365 ctx.cmd_push_constants(
366 frame.command_buffer(),
367 self.pipeline_layout.raw,
368 vk::ShaderStageFlags::VERTEX,
369 16,
370 &draw_params.transform_index.to_le_bytes(),
371 );
372 ctx.cmd_set_scissor(
373 frame.command_buffer(),
374 0,
375 &[draw_params.scissor],
376 );
377 ctx.cmd_draw_indexed(
378 frame.command_buffer(),
379 draw_params.index_count, 1, draw_params.index_offset, draw_params.vertex_offset as i32, 0, );
385 }
386 }
387
388 Ok(())
389 }
390}