From c70c1591db3db504e93322223bf07c8f8d7b1667 Mon Sep 17 00:00:00 2001 From: Janis Date: Sat, 18 Jan 2025 14:49:25 +0100 Subject: [PATCH] stuff: slight refactoring --- crates/game/Cargo.toml | 2 + crates/renderer/src/commands.rs | 4 +- crates/renderer/src/device.rs | 3 + crates/renderer/src/egui.rs | 2 +- crates/renderer/src/lib.rs | 644 +++------------------------- crates/renderer/src/render_graph.rs | 34 +- crates/renderer/src/util.rs | 9 + 7 files changed, 101 insertions(+), 597 deletions(-) diff --git a/crates/game/Cargo.toml b/crates/game/Cargo.toml index 1b5c411..bce3ae4 100644 --- a/crates/game/Cargo.toml +++ b/crates/game/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] winit = { workspace = true } tracing = { workspace = true } +smol = { workspace = true } +glam = { workspace = true } tracing-subscriber = { workspace = true } renderer = { path = "../renderer" } diff --git a/crates/renderer/src/commands.rs b/crates/renderer/src/commands.rs index 07ee5f8..6aae7b1 100644 --- a/crates/renderer/src/commands.rs +++ b/crates/renderer/src/commands.rs @@ -444,12 +444,12 @@ impl SingleUseCommand { ); } } - pub fn bind_vertices(&self, buffer: vk::Buffer, offset: u64) { + pub fn bind_vertex_buffers(&self, buffers: &[vk::Buffer], offsets: &[u64]) { assert_eq!(self.state(), CommandBufferState::Recording); unsafe { self.device() .dev() - .cmd_bind_vertex_buffers(self.buffer(), 0, &[buffer], &[offset]); + .cmd_bind_vertex_buffers(self.buffer(), 0, buffers, offsets); } } pub fn bind_indices(&self, buffer: vk::Buffer, offset: u64, kind: vk::IndexType) { diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs index 806271d..8487184 100644 --- a/crates/renderer/src/device.rs +++ b/crates/renderer/src/device.rs @@ -245,6 +245,9 @@ impl Device { pub fn graphics_queue(&self) -> &Queue { &self.0.main_queue } + pub fn transfer_queue(&self) -> &Queue { + &self.0.transfer_queue + } pub fn present_queue(&self) -> &Queue { &self.0.present_queue } diff --git a/crates/renderer/src/egui.rs b/crates/renderer/src/egui.rs index 2adaa6a..4d00d4c 100644 --- a/crates/renderer/src/egui.rs +++ b/crates/renderer/src/egui.rs @@ -712,7 +712,7 @@ pub fn egui_pass( cmd.bind_pipeline(&pipeline); cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32); - cmd.bind_vertices(vertices.buffer(), 0); + cmd.bind_vertex_buffers(&[vertices.buffer()], &[0]); cmd.push_constants( &pipeline_layout, vk::ShaderStageFlags::VERTEX, diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index c0f382b..6e9bc1f 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -43,9 +43,9 @@ mod egui_pass; mod images; mod pipeline; mod render_graph; -mod rendering; +pub mod rendering; mod sync; -mod util; +pub mod util; use device::{Device, DeviceOwned, DeviceQueueFamilies}; @@ -110,7 +110,7 @@ pub enum Error { Io(#[from] std::io::Error), } -type Result = core::result::Result; +pub type Result = core::result::Result; struct VkNameList<'a> { names: Vec<*const i8>, @@ -1072,7 +1072,7 @@ impl Drop for Surface { } } -struct SamplerCache { +pub struct SamplerCache { device: Device, samplers: HashMap, } @@ -1101,7 +1101,7 @@ impl SamplerCache { pub struct Vulkan { instance: Arc, - device: Device, + pub device: Device, samplers: SamplerCache, } @@ -1124,6 +1124,14 @@ impl Vulkan { const NSIGHT_INTERCEPTION_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_NV_nomad_release_public_2021_4_2"; + pub fn samplers(&self) -> &SamplerCache { + &self.samplers + } + + pub fn samplers_mut(&mut self) -> &mut SamplerCache { + &mut self.samplers + } + pub fn new( app_name: &str, instance_layers: &[&CStr], @@ -1232,6 +1240,7 @@ impl Vulkan { .features10( vk::PhysicalDeviceFeatures::default() .sampler_anisotropy(true) + .fill_mode_non_solid(true) .multi_draw_indirect(true), ) .features11(vk::PhysicalDeviceVulkan11Features::default().shader_draw_parameters(true)) @@ -2049,7 +2058,7 @@ pub struct Renderer { // thinkw: want renderer linked with display? then no (real) headless display: RawDisplayHandle, pub window_contexts: HashMap, - vulkan: Vulkan, + pub vulkan: Vulkan, } pub use vk::Extent2D; @@ -2066,447 +2075,59 @@ impl Renderer { }) } - pub fn draw_egui(&mut self, ctx: &egui::Context, output: egui::FullOutput) -> Result<()> { - let pool = commands::SingleUseCommandPool::new( - self.vulkan.device.clone(), - self.vulkan.device.graphics_queue().clone(), - ) - .unwrap(); - let cmd = pool.alloc().unwrap(); + pub async fn draw_with_graph( + &mut self, + window: &K, + pre_present_cb: F, + cb: G, + ) -> Result + where + K: core::hash::Hash + Eq, + W: core::hash::Hash + Eq + Borrow, + F: FnOnce(), + G: FnOnce(&mut Self, &mut render_graph::RenderGraph) -> T, + { + let dev = self.vulkan.device.clone(); - let cmd_objects = output - .textures_delta - .set - .iter() - .map(|(egui_id, delta)| { - let size = delta.image.size(); - let byte_size = size[0] * size[1] * 4; + let ctx = self.window_contexts.get(window).unwrap(); + let (frame, suboptimal) = ctx.current_swapchain.read().clone().acquire_image().await?; - let mut staging = buffers::Buffer::new( - self.vulkan.device.clone(), - buffers::BufferDesc { - name: Some(format!("egui-{egui_id:?}-staging-buf").into()), - size: byte_size as u64, - usage: vk::BufferUsageFlags::TRANSFER_SRC, - mem_usage: vk_mem::MemoryUsage::AutoPreferHost, - alloc_flags: vk_mem::AllocationCreateFlags::MAPPED - | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE - | vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT, - ..Default::default() - }, - ) - .expect("staging buffer"); - { - let mut mem = staging.map().expect("mapping staging buffer"); - match &delta.image { - egui::ImageData::Color(arc) => { - let slice = unsafe { - core::slice::from_raw_parts( - arc.pixels.as_ptr().cast::(), - arc.pixels.len() * size_of::(), - ) - }; - mem[..slice.len()].copy_from_slice(slice); - } - egui::ImageData::Font(font_image) => { - for (i, c) in font_image.srgba_pixels(None).enumerate() { - let bytes = c.to_array(); - mem[i * 4..(i + 1) * 4].copy_from_slice(&bytes); - } - } - } - } - - let sampled = if delta.is_whole() { - vk::ImageUsageFlags::SAMPLED - } else { - vk::ImageUsageFlags::TRANSFER_SRC - }; - - let texture = Arc::new( - images::Image::new( - self.vulkan.device.clone(), - images::ImageDesc { - name: Some(format!("egui-texture-{egui_id:?}").into()), - format: vk::Format::R8G8B8A8_UNORM, - extent: vk::Extent3D { - width: delta.image.width() as u32, - height: delta.image.height() as u32, - depth: 1, - }, - usage: sampled | vk::ImageUsageFlags::TRANSFER_DST, - mem_usage: vk_mem::MemoryUsage::AutoPreferDevice, - ..Default::default() - }, - ) - .expect("image creation"), - ); - - cmd.image_barrier( - texture.image(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::empty(), - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - None, - ); - cmd.copy_buffer_to_image( - staging.buffer(), - texture.image(), - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &[vk::BufferImageCopy { - buffer_offset: 0, - buffer_row_length: delta.image.width() as u32, - buffer_image_height: delta.image.height() as u32, - image_subresource: vk::ImageSubresourceLayers::default() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_array_layer(0) - .mip_level(0) - .layer_count(1), - image_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, - image_extent: vk::Extent3D { - width: texture.size().width, - height: texture.size().height, - depth: 1, - }, - }], - ); - - let id = self.egui_state.lookup_texture(*egui_id).unwrap_or_else(|| { - let id = texture::TextureId::new(); - - self.egui_state.textures.insert( - *egui_id, - EguiTextureInfo { - id, - options: delta.options, - }, - ); - - id - }); - - if let Some(pos) = delta.pos { - // SAFETY: must exist because image is not whole. - let existing_texture = self.texture_handler.textures.get(&id).cloned().unwrap(); - - cmd.image_barrier( - texture.image(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_READ, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - None, - ); - cmd.image_barrier( - existing_texture.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::empty(), - vk::AccessFlags2::empty(), - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - None, - ); - cmd.blit_images( - &texture, - util::Rect2D::new(0, 0, texture.width() as i32, texture.height() as i32), - &existing_texture, - util::Rect2D::new_from_size( - glam::ivec2(pos[0] as i32, pos[1] as i32), - glam::ivec2(texture.width() as i32, texture.height() as i32), - ), - ); - cmd.image_barrier( - existing_texture.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::PipelineStageFlags2::FRAGMENT_SHADER, - vk::AccessFlags2::SHADER_SAMPLED_READ, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - None, - ); - } else { - cmd.image_barrier( - texture.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::PipelineStageFlags2::FRAGMENT_SHADER, - vk::AccessFlags2::SHADER_SAMPLED_READ, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - None, - ); - self.texture_handler - .insert_image_with_id(id, texture.clone()); - tracing::trace!("new texture for egui: {egui_id:?} -> {id:?}"); - } - - (staging, texture) - }) - .collect::>(); - - let draw_data = ctx.tessellate(output.shapes, output.pixels_per_point); - - #[repr(C)] - #[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)] - struct Vertex { - pos: glam::Vec2, - uv: glam::Vec2, - color: egui::epaint::Color32, + if suboptimal { + tracing::warn!( + "swapchain ({:?}) is suboptimal!", + ctx.current_swapchain.read().swapchain + ); } - #[repr(transparent)] - #[derive(Debug, Clone, Copy)] - struct DrawCall(vk::DrawIndexedIndirectCommand); - unsafe impl bytemuck::Zeroable for DrawCall {} - unsafe impl bytemuck::Pod for DrawCall {} + let [r, g, b] = + rand::prelude::StdRng::seed_from_u64(ctx.surface.surface.as_raw()).gen::<[f32; 3]>(); + let clear_color = Rgba([r, g, b, 1.0]); - 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; - }; + let mut rg = render_graph::RenderGraph::new(); + let framebuffer = rg.import_image(frame.image.clone(), Access::undefined()); + rg.mark_as_output(framebuffer, Access::present()); + rg.framebuffer = Some(framebuffer); - 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, - })); + render_graph::clear_pass(&mut rg, clear_color, framebuffer); - 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, - })); + let t = cb(self, &mut rg); - indices.extend(mesh.indices); - let texture = self - .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 cmds = rg.resolve(dev.clone())?; - let num_draw_calls = draw_calls.len(); - let device = self.vulkan.device.clone(); - let (draw_staging, vertices, indices, draw_calls, texture_ids) = { - let vertices_size = vertices.len() * size_of::(); - let indices_size = indices.len() * size_of::(); - let draw_calls_size = draw_calls.len() * size_of::(); + let future = cmds.submit( + Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)), + Some(frame.release), + Arc::new(sync::Fence::create(dev.clone())?), + )?; - let staging_size = vertices_size + indices_size + draw_calls_size; + // call pre_present_notify + pre_present_cb(); - let mut staging = buffers::Buffer::new( - device.clone(), - buffers::BufferDesc { - name: Some("egui-draw-staging".into()), - size: staging_size as u64, - usage: vk::BufferUsageFlags::TRANSFER_SRC, - mem_usage: vk_mem::MemoryUsage::AutoPreferHost, - alloc_flags: vk_mem::AllocationCreateFlags::MAPPED - | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE - | vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT, - ..Default::default() - }, - )?; + future.await; + let wait = Some(frame.release); + frame.present(wait)?; - { - let mut map = staging.map()?; - - let (st_vertices, rest) = map.split_at_mut(vertices_size); - let (st_indices, st_drawcalls) = rest.split_at_mut(indices_size); - st_vertices.copy_from_slice(bytemuck::cast_slice(&vertices)); - st_indices.copy_from_slice(bytemuck::cast_slice(&indices)); - st_drawcalls.copy_from_slice(bytemuck::cast_slice(&draw_calls)); - } - - let vertices = buffers::Buffer::new( - device.clone(), - buffers::BufferDesc { - name: Some("egui-draw-vertices".into()), - size: vertices_size as u64, - usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, - mem_usage: vk_mem::MemoryUsage::AutoPreferDevice, - ..Default::default() - }, - )?; - let indices = buffers::Buffer::new( - device.clone(), - buffers::BufferDesc { - name: Some("egui-draw-indices".into()), - size: indices_size as u64, - usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER, - mem_usage: vk_mem::MemoryUsage::AutoPreferDevice, - ..Default::default() - }, - )?; - let draw_calls = buffers::Buffer::new( - device.clone(), - buffers::BufferDesc { - name: Some("egui-draw-draw_calls".into()), - size: draw_calls_size as u64, - usage: vk::BufferUsageFlags::TRANSFER_DST - | vk::BufferUsageFlags::INDIRECT_BUFFER, - mem_usage: vk_mem::MemoryUsage::AutoPreferDevice, - ..Default::default() - }, - )?; - - cmd.copy_buffers( - staging.buffer(), - vertices.buffer(), - &[vk::BufferCopy { - src_offset: 0, - dst_offset: 0, - size: vertices_size as u64, - }], - ); - cmd.copy_buffers( - staging.buffer(), - indices.buffer(), - &[vk::BufferCopy { - src_offset: vertices_size as u64, - dst_offset: 0, - size: indices_size as u64, - }], - ); - cmd.copy_buffers( - staging.buffer(), - draw_calls.buffer(), - &[vk::BufferCopy { - src_offset: (vertices_size + indices_size) as u64, - dst_offset: 0, - size: draw_calls_size as u64, - }], - ); - - let mut texture_ids = buffers::Buffer::new( - device.clone(), - buffers::BufferDesc { - name: Some("egui-draw-texture_ids".into()), - size: (textures_indices.len() * size_of::()) as u64, - usage: vk::BufferUsageFlags::STORAGE_BUFFER, - mem_usage: vk_mem::MemoryUsage::AutoPreferDevice, - alloc_flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE, - ..Default::default() - }, - )?; - { - let mut map = texture_ids.map()?; - map.copy_from_slice(bytemuck::cast_slice(&textures_indices)); - } - - (staging, vertices, indices, draw_calls, texture_ids) - }; - - let descriptor_infos = textures - .values() - .map(|entry| { - let texture = self.texture_handler.get_texture(entry.id).unwrap(); - let info = vk::DescriptorImageInfo { - sampler: self - .vulkan - .samplers - .get_sampler(entry.into_sampler_desc()) - .unwrap(), - image_view: texture - .get_view(images::ImageViewDesc { - kind: vk::ImageViewType::TYPE_2D, - format: texture.format(), - aspect: vk::ImageAspectFlags::COLOR, - mip_range: (0..1).into(), - layer_range: (0..1).into(), - ..Default::default() - }) - .unwrap(), - image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - }; - - info - }) - .collect::>(); - - let uniform_info = vk::DescriptorBufferInfo { - buffer: texture_ids.buffer(), - offset: 0, - range: texture_ids.len(), - }; - - let descriptor_writes = descriptor_infos - .iter() - .enumerate() - .map(|(i, info)| { - vk::WriteDescriptorSet::default() - .image_info(core::slice::from_ref(info)) - .descriptor_count(1) - .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .dst_set(self.egui_state.descriptor_set) - .dst_binding(EguiState::TEXTURE_BINDING) - .dst_array_element(i as u32) - }) - .chain(core::iter::once({ - vk::WriteDescriptorSet::default() - .buffer_info(core::slice::from_ref(&uniform_info)) - .descriptor_count(1) - .dst_binding(EguiState::UNIFORM_BINDING) - .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) - .dst_array_element(0) - .dst_set(self.egui_state.descriptor_set) - })) - .collect::>(); - - unsafe { - device.dev().update_descriptor_sets(&descriptor_writes, &[]); - } - - let to_remove_tex_ids = output - .textures_delta - .free - .iter() - .filter_map(|id| self.egui_state.textures.get(id).cloned()) - .map(|entry| entry.id) - .collect::>(); - - self.egui_state.render_state = Some(EguiRenderState { - vertices, - indices, - draw_calls, - num_draw_calls, - texture_ids, - textures_to_free: to_remove_tex_ids, - }); - - let fence = Arc::new(sync::Fence::create(device.clone()).unwrap()); - let future = cmd.submit_async(None, None, fence).unwrap(); - - future.block()?; - - black_box((cmd_objects, draw_staging)); - // free after drawing - Ok(()) + Ok(t) } pub fn debug_draw_egui( @@ -2588,159 +2209,6 @@ impl Renderer { Ok(()) } - pub fn debug_draw(&mut self, window: &K, pre_present_cb: F) -> Result<()> - where - K: core::hash::Hash + Eq, - W: core::hash::Hash + Eq + Borrow, - { - let dev = self.vulkan.device.clone(); - let pool = commands::SingleUseCommandPool::new(dev.clone(), dev.graphics_queue().clone())?; - - if let Some(ctx) = self.window_contexts.get(window) { - let (frame, suboptimal) = - smol::block_on(ctx.current_swapchain.read().clone().acquire_image())?; - - if suboptimal { - tracing::warn!( - "swapchain ({:?}) is suboptimal!", - ctx.current_swapchain.read().swapchain - ); - } - - let [r, g, b] = rand::prelude::StdRng::seed_from_u64(ctx.surface.surface.as_raw()) - .gen::<[f32; 3]>(); - let clear_color = Rgba([r, g, b, 1.0]); - - let egui_ctx = self.egui_state.render_state.take(); - - let cmd = util::timed("record command buffer", || { - let cmd = pool.alloc()?; - cmd.image_barrier( - frame.image.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::empty(), - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - None, - ); - cmd.clear_color_image( - frame.image.handle(), - frame.format, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - clear_color, - &[images::SUBRESOURCERANGE_COLOR_ALL], - ); - cmd.image_barrier( - frame.image.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::TRANSFER, - vk::AccessFlags2::TRANSFER_WRITE, - vk::PipelineStageFlags2::FRAGMENT_SHADER, - vk::AccessFlags2::SHADER_WRITE, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, - None, - ); - - if let Some(ctx) = egui_ctx.as_ref() { - _ = &ctx.texture_ids; - - let color_attachment = &vk::RenderingAttachmentInfo::default() - .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .image_view(frame.view) - .load_op(vk::AttachmentLoadOp::LOAD) - .store_op(vk::AttachmentStoreOp::STORE); - - cmd.begin_rendering( - vk::RenderingInfo::default() - .color_attachments(core::slice::from_ref(color_attachment)) - .layer_count(1) - .render_area(vk::Rect2D::default().extent(frame.swapchain.extent)), - ); - - cmd.set_scissors(&[vk::Rect2D::default() - .offset(vk::Offset2D::default()) - .extent(frame.swapchain.extent)]); - - cmd.set_viewport(&[vk::Viewport::default() - .x(0.0) - .y(0.0) - .min_depth(0.0) - .max_depth(1.0) - .width(frame.swapchain.extent.width as f32) - .height(frame.swapchain.extent.height as f32)]); - - cmd.bind_pipeline(&self.egui_state.pipeline); - cmd.bind_indices(ctx.indices.buffer(), 0, vk::IndexType::UINT32); - cmd.bind_vertices(ctx.vertices.buffer(), 0); - cmd.push_constants( - &self.egui_state.pipeline_layout, - vk::ShaderStageFlags::VERTEX, - 0, - bytemuck::cast_slice( - &[ - frame.swapchain.extent.width as f32, - frame.swapchain.extent.height as f32, - ] - .map(|f| f.to_bits()), - ), - ); - cmd.bind_descriptor_sets( - &self.egui_state.pipeline_layout, - vk::PipelineBindPoint::GRAPHICS, - &[self.egui_state.descriptor_set], - ); - cmd.draw_indexed_indirect( - ctx.draw_calls.buffer(), - 0, - ctx.num_draw_calls as u32, - size_of::() as u32, - ); - - cmd.end_rendering(); - } - - cmd.image_barrier( - frame.image.handle(), - vk::ImageAspectFlags::COLOR, - vk::PipelineStageFlags2::FRAGMENT_SHADER, - vk::AccessFlags2::SHADER_WRITE, - vk::PipelineStageFlags2::BOTTOM_OF_PIPE, - vk::AccessFlags2::empty(), - vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, - vk::ImageLayout::PRESENT_SRC_KHR, - None, - ); - - Result::Ok(cmd) - })?; - - let future = cmd.submit_async( - Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)), - Some(frame.release), - Arc::new(sync::Fence::create(dev.clone())?), - )?; - - // call pre_present_notify - pre_present_cb(); - - let wait = Some(frame.release); - frame.present(wait)?; - future.block()?; - - egui_ctx.map(|ctx| { - for id in ctx.textures_to_free { - self.texture_handler.remove_texture(id); - } - }); - } - - Ok(()) - } - pub fn new_window_context( &mut self, extent: vk::Extent2D, diff --git a/crates/renderer/src/render_graph.rs b/crates/renderer/src/render_graph.rs index ad45ddc..f077889 100644 --- a/crates/renderer/src/render_graph.rs +++ b/crates/renderer/src/render_graph.rs @@ -43,7 +43,7 @@ impl From for GraphResource { #[derive(Default, Debug, PartialEq, Eq)] pub enum GraphResource { - Framebuffer(Arc), + Framebuffer(Arc), ImportedImage(Arc), ImportedBuffer(Arc), Image(Arc), @@ -63,7 +63,7 @@ impl GraphResource { match self { GraphResource::Framebuffer(swapchain_frame) => { - (swapchain_frame.index, swapchain_frame.image.handle()).hash(&mut state) + (swapchain_frame.handle()).hash(&mut state) } GraphResource::ImportedImage(image) => image.handle().hash(&mut state), GraphResource::ImportedBuffer(buffer) => buffer.handle().hash(&mut state), @@ -95,6 +95,7 @@ pub struct RenderContext<'a> { pub device: device::Device, pub cmd: commands::SingleUseCommand, pub resources: &'a [GraphResource], + pub framebuffer: Option, } impl RenderContext<'_> { @@ -102,7 +103,7 @@ impl RenderContext<'_> { self.resources.get(id.0 as usize).and_then(|res| match res { GraphResource::ImportedImage(arc) => Some(arc), GraphResource::Image(image) => Some(image), - GraphResource::Framebuffer(fb) => Some(&fb.image), + GraphResource::Framebuffer(fb) => Some(fb), _ => None, }) } @@ -113,6 +114,14 @@ impl RenderContext<'_> { _ => None, }) } + pub fn get_framebuffer(&self) -> Option<&Image> { + self.framebuffer + .and_then(|rid| self.resources.get(rid.0 as usize)) + .and_then(|res| match res { + GraphResource::Framebuffer(arc) => Some(arc.as_ref()), + _ => None, + }) + } } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)] @@ -349,6 +358,7 @@ pub struct RenderGraph { /// the rendergraph produces these resources. Any passes on which these /// outputs do not depend are pruned. outputs: BTreeMap, + pub(crate) framebuffer: Option, } impl RenderGraph { @@ -360,9 +370,14 @@ impl RenderGraph { resources: Vec::new(), pass_descs, outputs: BTreeMap::new(), + framebuffer: None, } } + pub fn get_framebuffer(&self) -> Option { + self.framebuffer + } + fn get_next_resource_id(&mut self) -> GraphResourceId { GraphResourceId(self.resources.len() as u32) } @@ -406,8 +421,14 @@ impl RenderGraph { self.import_resource(res, access) } - pub fn import_framebuffer(&mut self, frame: Arc) -> GraphResourceId { - self.import_resource(GraphResource::Framebuffer(frame), Access::undefined()) + pub fn import_framebuffer(&mut self, frame: &SwapchainFrame) -> GraphResourceId { + let rid = self.import_resource( + GraphResource::Framebuffer(frame.image.clone()), + Access::undefined(), + ); + self.mark_as_output(rid, Access::present()); + self.framebuffer = Some(rid); + rid } pub fn add_pass(&mut self, pass: PassDesc) { @@ -500,6 +521,7 @@ impl RenderGraph { device: device.clone(), cmd, resources, + framebuffer: self.framebuffer, }; for pass in passes { @@ -538,7 +560,7 @@ impl RenderGraph { ) { let barrier: Barrier = match res { GraphResource::Framebuffer(arc) => { - image_barrier(arc.image.handle(), arc.image.format(), from, to, None).into() + image_barrier(arc.handle(), arc.format(), from, to, None).into() } GraphResource::ImportedImage(arc) => { image_barrier(arc.handle(), arc.format(), from, to, None).into() diff --git a/crates/renderer/src/util.rs b/crates/renderer/src/util.rs index bc63064..15553c8 100644 --- a/crates/renderer/src/util.rs +++ b/crates/renderer/src/util.rs @@ -1,6 +1,7 @@ use std::ops::{Deref, DerefMut}; use ash::vk; +use bytemuck::{Pod, Zeroable}; #[macro_export] macro_rules! def_monotonic_id { @@ -350,8 +351,13 @@ pub fn timed T>(label: &str, f: F) -> T { } #[derive(Debug, Clone, Copy)] +#[repr(transparent)] pub struct Rgba(pub [f32; 4]); +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(transparent)] +pub struct Rgba8(pub [u8; 4]); + impl std::hash::Hash for Rgba { fn hash(&self, state: &mut H) { self.0.map(|f| hash_f32(state, f)); @@ -369,6 +375,9 @@ impl Rgba { pub fn into_f32(&self) -> [f32; 4] { self.0 } + pub fn into_u8(&self) -> Rgba8 { + Rgba8(self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u8)) + } pub fn into_snorm(&self) -> [f32; 4] { self.0.map(|f| (f - 0.5) * 2.0) }