diff --git a/crates/renderer/src/render_graph/graph_builder.rs b/crates/renderer/src/render_graph/graph_builder.rs new file mode 100644 index 0000000..246512b --- /dev/null +++ b/crates/renderer/src/render_graph/graph_builder.rs @@ -0,0 +1,315 @@ +use std::{cell::UnsafeCell, collections::BTreeMap, marker::PhantomData}; + +use ash::vk; +use derive_more::derive::{Deref, DerefMut}; + +use crate::{ + buffers, images, + render_graph::{ + recorder::CommandList, + resources::{self, ResourceId}, + }, +}; + +pub struct GraphResourceRegistry { + images: BTreeMap>, + views: BTreeMap>, + buffers: BTreeMap>, +} + +#[derive(Deref, DerefMut)] +struct StagingBuffer<'a> { + id: ResourceId, + #[deref] + #[deref_mut] + buffer: &'a mut buffers::Buffer, +} + +#[derive(Deref, DerefMut)] +struct Buffer<'a> { + id: ResourceId, + #[deref] + #[deref_mut] + buffer: &'a mut buffers::Buffer, +} + +pub struct GraphBuilder<'r> { + _pd: PhantomData, +} +impl<'r> GraphBuilder<'r> { + fn make_command_list<'cmd>(&self) -> CommandList<'cmd> { + todo!() + } + fn make_staging_buffer(&self, _size: u64) -> StagingBuffer<'r> { + todo!() + } + + fn make_buffer( + &self, + _size: u64, + _usage: vk::BufferUsageFlags, + _location: gpu_allocator::MemoryLocation, + ) -> Buffer<'r> { + todo!() + } + + // we need to know which queue currently owns this buffer to be able to + // transfer it to the correct queue family when using it + fn import_buffer(&self, _buffer: buffers::Buffer, _owning_queue: Option) -> Buffer<'r> { + todo!() + } +} + +mod api_demo { + + use crate::{EguiState, pipeline::Pipeline, render_graph::commands}; + + use super::*; + use ash::vk::{self, BufferUsageFlags}; + use gpu_allocator::MemoryLocation; + use indexmap::IndexMap; + + fn egui_graph<'a>( + egui_state: &mut EguiState, + draw_data: Vec, + builder: GraphBuilder, + render_target: ResourceId, + extent: (u32, u32), + pipeline: &'a Pipeline, + descriptor: vk::DescriptorSet, + ) -> CommandList<'a> { + #[repr(C)] + #[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)] + struct Vertex { + pos: glam::Vec2, + uv: glam::Vec2, + color: egui::epaint::Color32, + } + + #[repr(transparent)] + #[derive(Debug, Clone, Copy)] + struct DrawCall(vk::DrawIndexedIndirectCommand); + unsafe impl bytemuck::Zeroable for DrawCall {} + unsafe impl bytemuck::Pod for DrawCall {} + + let mut vertices = Vec::new(); + let mut indices = Vec::new(); + let mut draw_calls = Vec::new(); + let mut textures = IndexMap::new(); + let mut textures_indices = Vec::new(); + for draw in draw_data { + let egui::epaint::Primitive::Mesh(mesh) = draw.primitive else { + continue; + }; + + draw_calls.push(DrawCall(vk::DrawIndexedIndirectCommand { + index_count: mesh.indices.len() as u32, + instance_count: 1, + first_index: indices.len() as u32, + vertex_offset: vertices.len() as i32, + first_instance: 0, + })); + + vertices.extend(mesh.vertices.iter().map(|v| Vertex { + pos: glam::vec2(v.pos.x, v.pos.y), + uv: glam::vec2(v.uv.x, v.uv.y), + color: v.color, + })); + + indices.extend(mesh.indices); + let texture = egui_state.textures.get(&mesh.texture_id).cloned().unwrap(); + if !textures.contains_key(&texture.id) { + textures.insert(texture.id, texture); + } + let idx = textures.get_index_of(&texture.id).unwrap(); + textures_indices.push(idx as u32); + } + + let vertex_size = vertices.len() * size_of::(); + let index_size = indices.len() * size_of::(); + let draw_calls_size = draw_calls.len() * size_of::(); + let textures_indices_size = textures_indices.len() * size_of::(); + let staging_size = vertex_size + index_size + draw_calls_size + textures_indices_size; + let mut staging = builder.make_staging_buffer(staging_size as u64); + + use core::io::BorrowedBuf; + let mut buf = BorrowedBuf::from(staging.map_mut().unwrap()); + let mut cursor = buf.unfilled(); + cursor.append(bytemuck::cast_slice(&vertices)); + cursor.append(bytemuck::cast_slice(&indices)); + cursor.append(bytemuck::cast_slice(&draw_calls)); + cursor.append(bytemuck::cast_slice(&textures_indices)); + + let vertex_buffer = builder.make_buffer( + vertex_size as u64, + BufferUsageFlags::TRANSFER_DST | BufferUsageFlags::VERTEX_BUFFER, + MemoryLocation::GpuOnly, + ); + let index_buffer = builder.make_buffer( + index_size as u64, + BufferUsageFlags::TRANSFER_DST | BufferUsageFlags::INDEX_BUFFER, + MemoryLocation::GpuOnly, + ); + let indirect_buffer = builder.make_buffer( + draw_calls_size as u64, + BufferUsageFlags::TRANSFER_DST | BufferUsageFlags::INDIRECT_BUFFER, + MemoryLocation::GpuOnly, + ); + let texture_indices = builder.make_buffer( + textures_indices_size as u64, + BufferUsageFlags::TRANSFER_DST | BufferUsageFlags::STORAGE_BUFFER, + MemoryLocation::GpuOnly, + ); + + let mut cmd = builder.make_command_list(); + cmd.push(commands::Copy { + src: resources::BufferSlice { + buffer: resources::Buffer(staging.id), + range: resources::BufferRange { + offset: 0, + size: vertex_size as u64, + }, + }, + dst: resources::BufferSlice { + buffer: resources::Buffer(vertex_buffer.id), + range: resources::BufferRange { + offset: 0, + size: vertex_size as u64, + }, + }, + }); + + cmd.push(commands::Copy { + src: resources::BufferSlice { + buffer: resources::Buffer(staging.id), + range: resources::BufferRange { + offset: vertex_size as u64, + size: (vertex_size + index_size) as u64, + }, + }, + dst: resources::BufferSlice { + buffer: resources::Buffer(index_buffer.id), + range: resources::BufferRange { + offset: 0, + size: index_size as u64, + }, + }, + }); + + cmd.push(commands::Copy { + src: resources::BufferSlice { + buffer: resources::Buffer(staging.id), + range: resources::BufferRange { + offset: (vertex_size + index_size) as u64, + size: draw_calls_size as u64, + }, + }, + dst: resources::BufferSlice { + buffer: resources::Buffer(indirect_buffer.id), + range: resources::BufferRange { + offset: 0, + size: draw_calls_size as u64, + }, + }, + }); + + cmd.push(commands::Copy { + src: resources::BufferSlice { + buffer: resources::Buffer(staging.id), + range: resources::BufferRange { + offset: (vertex_size + index_size + draw_calls_size) as u64, + size: textures_indices_size as u64, + }, + }, + dst: resources::BufferSlice { + buffer: resources::Buffer(texture_indices.id), + range: resources::BufferRange { + offset: 0, + size: textures_indices_size as u64, + }, + }, + }); + + let mut pass_cmd = cmd.begin_rendering( + vec![resources::TextureRegion { + texture: resources::Texture(render_target), + range: resources::TextureRange { + aspect: vk::ImageAspectFlags::COLOR, + mip_levels: (0..).into(), + array_layers: (0..).into(), + origin: (0, 0, 0), + extent: (extent.0, extent.1, 1), + }, + }], + None, + None, + extent, + 1, + ); + + pass_cmd.push(commands::SetScissor { + x: 0, + y: 0, + width: extent.0, + height: extent.1, + }); + pass_cmd.push(commands::SetViewport { + x: 0.0, + y: 0.0, + width: extent.0 as f32, + height: extent.1 as f32, + min_depth: 0.0, + max_depth: 1.0, + }); + + fn factory() -> T { + unimplemented!() + } + pass_cmd.push(commands::BindPipeline( + pipeline.raw(), + pipeline.bind_point(), + )); + pass_cmd.push(commands::BindDescriptorSets { + pipeline_layout: pipeline.layout().raw(), + sets: vec![descriptor], + first_set: 0, + bind_point: vk::PipelineBindPoint::GRAPHICS, + }); + pass_cmd.push(commands::PushConstants { + pipeline_layout: pipeline.layout().raw(), + stage_flags: vk::ShaderStageFlags::VERTEX, + offset: 0, + data: bytemuck::pod_collect_to_vec( + &[extent.0 as f32, extent.1 as f32].map(f32::to_bits), + ), + }); + pass_cmd.push(commands::Draw { + data: commands::DrawIndexedIndirectData { + indirect_buffer: resources::Buffer(indirect_buffer.id).full_slice(), + count: draw_calls.len() as u32, + stride: size_of::() as u32, + }, + vertex_buffers: vec![resources::BufferSlice { + buffer: resources::Buffer(vertex_buffer.id), + range: resources::BufferRange { + offset: 0, + size: vertex_size as u64, + }, + }], + index_buffer: Some(( + resources::BufferSlice { + buffer: resources::Buffer(index_buffer.id), + range: resources::BufferRange { + offset: 0, + size: index_size as u64, + }, + }, + commands::IndexFormat::Uint32, + )), + }); + + pass_cmd.finalise(); + + cmd + } +}