diff --git a/crates/renderer/src/buffers.rs b/crates/renderer/src/buffers.rs index a1b1c44..2d5cb50 100644 --- a/crates/renderer/src/buffers.rs +++ b/crates/renderer/src/buffers.rs @@ -1,12 +1,67 @@ use std::{ + borrow::Cow, ops::{Deref, DerefMut}, sync::Arc, }; use ash::{prelude::VkResult, vk}; +use itertools::Itertools; use vk_mem::Alloc; -use crate::{define_device_owned_handle, device::DeviceOwned, Device}; +use crate::{ + define_device_owned_handle, + device::{DeviceOwned, QueueFlags}, + Device, +}; + +#[derive(Clone)] +pub struct BufferDesc { + pub flags: vk::BufferCreateFlags, + pub name: Option>, + pub size: u64, + pub usage: vk::BufferUsageFlags, + pub queue_families: QueueFlags, + + pub mem_usage: vk_mem::MemoryUsage, + pub alloc_flags: vk_mem::AllocationCreateFlags, +} + +impl std::fmt::Debug for BufferDesc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BufferDesc") + .field("flags", &self.flags) + .field("name", &self.name) + .field("size", &self.size) + .field("usage", &self.usage) + .field("queue_families", &self.queue_families) + .field("mem_usage", &self.mem_usage) + .field_with("alloc_flags", |f| { + write!( + f, + "{}", + self.alloc_flags + .iter_names() + .map(|(name, _)| name) + .format(" | ") + ) + }) + .finish() + } +} + +impl Default for BufferDesc { + fn default() -> Self { + Self { + flags: Default::default(), + name: Default::default(), + size: Default::default(), + usage: Default::default(), + queue_families: QueueFlags::empty(), + alloc_flags: vk_mem::AllocationCreateFlags::empty(), + mem_usage: vk_mem::MemoryUsage::Auto, + } + } +} define_device_owned_handle! { #[derive(Debug)] @@ -19,15 +74,9 @@ define_device_owned_handle! { } impl Buffer { - pub fn new( - device: Device, - size: usize, - usage: vk::BufferUsageFlags, - queue_families: &[u32], - memory_usage: vk_mem::MemoryUsage, - alloc_flags: vk_mem::AllocationCreateFlags, - name: Option>, - ) -> VkResult> { + pub fn new(device: Device, desc: BufferDesc) -> VkResult> { + let queue_families = device.queue_families().family_indices(desc.queue_families); + let sharing_mode = if queue_families.len() > 1 { vk::SharingMode::CONCURRENT } else { @@ -37,24 +86,20 @@ impl Buffer { let (buffer, allocation) = unsafe { device.alloc().create_buffer( &vk::BufferCreateInfo::default() - .size(size as u64) - .usage(usage) - .queue_family_indices(queue_families) + .size(desc.size) + .usage(desc.usage) + .queue_family_indices(&queue_families) .sharing_mode(sharing_mode), &vk_mem::AllocationCreateInfo { - flags: alloc_flags, - usage: memory_usage, + flags: desc.alloc_flags, + usage: desc.mem_usage, ..Default::default() }, )? }; Ok(Arc::new(Self::construct( - device, - buffer, - name, - allocation, - size as u64, + device, buffer, desc.name, allocation, desc.size, )?)) } diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs index 9b36997..a072c54 100644 --- a/crates/renderer/src/device.rs +++ b/crates/renderer/src/device.rs @@ -40,6 +40,41 @@ impl DeviceQueueFamilies { pub fn transfer_familty(&self) -> u32 { self.transfer.0 } + + pub fn family_indices(&self, flags: QueueFlags) -> ArrayVec<[u32; 4]> { + let mut indices = array_vec!([u32; 4]); + if flags.contains(QueueFlags::GRAPHICS) { + indices.push(self.graphics_familty()); + } + if flags.contains(QueueFlags::PRESENT) { + indices.push(self.present_familty()); + } + if flags.contains(QueueFlags::ASYNC_COMPUTE) { + indices.push(self.async_compute_familty()); + } + if flags.contains(QueueFlags::TRANSFER) { + indices.push(self.transfer_familty()); + } + + let unique_len = indices.partition_dedup().0.len(); + indices.drain(unique_len..); + + indices + } +} + +bitflags::bitflags! { + #[repr(transparent)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct QueueFlags: u32 { + const GRAPHICS = 1 << 0; + const PRESENT = 1 << 1; + const ASYNC_COMPUTE = 1 << 2; + const TRANSFER = 1 << 3; + + const NONE = 0; + const PRESENT_GRAPHICS = 1 << 0 | 1 << 1; + } } #[repr(transparent)] @@ -186,6 +221,9 @@ impl Device { pub fn dev(&self) -> &ash::Device { &self.0.device } + pub fn instance(&self) -> &Arc { + &self.0.instance + } pub fn swapchain(&self) -> &khr::swapchain::Device { &self.0.swapchain } diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index 7c85243..ea8f7d9 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -1,6 +1,9 @@ use std::borrow::Cow; -use crate::{define_device_owned_handle, device::DeviceOwned}; +use crate::{ + define_device_owned_handle, + device::{DeviceOwned, QueueFlags}, +}; use super::Device; use ash::{prelude::*, vk}; @@ -8,7 +11,7 @@ use itertools::Itertools; use vk_mem::Alloc; #[derive(Clone)] -pub struct ImageDesc<'a> { +pub struct ImageDesc { pub flags: vk::ImageCreateFlags, pub name: Option>, pub format: vk::Format, @@ -19,14 +22,14 @@ pub struct ImageDesc<'a> { pub extent: vk::Extent3D, pub tiling: vk::ImageTiling, pub usage: vk::ImageUsageFlags, - pub queue_families: &'a [u32], + pub queue_families: QueueFlags, pub layout: vk::ImageLayout, pub mem_usage: vk_mem::MemoryUsage, pub alloc_flags: vk_mem::AllocationCreateFlags, } -impl<'a> std::fmt::Debug for ImageDesc<'a> { +impl<'a> std::fmt::Debug for ImageDesc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ImageDesc") .field("flags", &self.flags) @@ -56,7 +59,7 @@ impl<'a> std::fmt::Debug for ImageDesc<'a> { } } -impl<'a> Default for ImageDesc<'a> { +impl Default for ImageDesc { fn default() -> Self { Self { flags: Default::default(), @@ -69,7 +72,7 @@ impl<'a> Default for ImageDesc<'a> { extent: Default::default(), tiling: vk::ImageTiling::OPTIMAL, usage: Default::default(), - queue_families: &[], + queue_families: QueueFlags::empty(), layout: vk::ImageLayout::UNDEFINED, alloc_flags: vk_mem::AllocationCreateFlags::empty(), mem_usage: vk_mem::MemoryUsage::Auto, @@ -106,6 +109,15 @@ impl Image { mem_usage, alloc_flags, } = desc; + + let queue_families = device.queue_families().family_indices(queue_families); + + let sharing_mode = if queue_families.len() > 1 { + vk::SharingMode::CONCURRENT + } else { + vk::SharingMode::EXCLUSIVE + }; + let info = &vk::ImageCreateInfo::default() .flags(flags) .image_type(kind) @@ -115,12 +127,8 @@ impl Image { .initial_layout(layout) .tiling(tiling) .usage(usage) - .sharing_mode(if queue_families.len() > 1 { - vk::SharingMode::CONCURRENT - } else { - vk::SharingMode::EXCLUSIVE - }) - .queue_family_indices(queue_families) + .sharing_mode(sharing_mode) + .queue_family_indices(&queue_families) .array_layers(array_layers) .mip_levels(mip_levels); diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 97991a1..9d89579 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -4,7 +4,8 @@ let_chains, negative_impls, map_try_insert, - debug_closure_helpers + debug_closure_helpers, + slice_partition_dedup )] use std::{ @@ -18,7 +19,6 @@ use std::{ atomic::{AtomicU32, AtomicU64}, Arc, }, - time::Instant, }; use egui::Color32; @@ -61,7 +61,7 @@ mod texture { Device, }; - def_monotonic_id!(TextureId); + def_monotonic_id!(pub TextureId); pub struct Texture { id: TextureId, @@ -125,7 +125,7 @@ mod texture { } } -use render_graph::Rgba; +use util::Rgba; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -526,9 +526,9 @@ impl SwapchainHandle { } } +#[derive(Debug)] pub struct Swapchain { device: Device, - instance: Arc, // has a strong ref to the surface because the surface may not outlive the swapchain surface: Arc, swapchain: SwapchainHandle, @@ -610,6 +610,7 @@ struct SwapchainParams { extent: vk::Extent2D, } +#[derive(Debug)] #[must_use = "This struct represents an acquired image from the swapchain and must be presented in order to free resources on the device."] pub struct SwapchainFrame { @@ -696,17 +697,15 @@ impl Swapchain { } pub fn new( - instance: Arc, device: Device, surface: Arc, pdev: vk::PhysicalDevice, extent: vk::Extent2D, ) -> Result { - Self::create(instance, device, surface, pdev, Some(extent), None) + Self::create(device, surface, pdev, Some(extent), None) } fn create( - instance: Arc, device: Device, surface: Arc, pdev: vk::PhysicalDevice, @@ -720,7 +719,12 @@ impl Swapchain { image_count, min_image_count, extent, - } = Self::get_swapchain_params_from_surface(&instance, surface.surface, pdev, extent)?; + } = Self::get_swapchain_params_from_surface( + device.instance(), + surface.surface, + pdev, + extent, + )?; let (swapchain, images) = { let lock = old_swapchain.as_ref().map(|handle| handle.lock()); @@ -841,7 +845,6 @@ impl Swapchain { tracing::debug!("fences: {fences:?}"); Ok(Self { - instance, device, surface, swapchain, @@ -870,7 +873,6 @@ impl Swapchain { fn recreate(&self, extent: Option) -> Result { Self::create( - self.instance.clone(), self.device.clone(), self.surface.clone(), self.device.phy(), @@ -1035,6 +1037,14 @@ pub struct Surface { surface: vk::SurfaceKHR, } +impl Debug for Surface { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Surface") + .field("surface", &self.surface) + .finish() + } +} + impl Surface { #[allow(dead_code)] fn headless(instance: Arc) -> Result { @@ -1734,7 +1744,6 @@ impl WindowContext { let surface = Arc::new(Surface::create(instance.clone(), display, window_handle)?); let swapchain = Arc::new(Swapchain::new( - instance, device.clone(), surface.clone(), device.phy(), @@ -2081,16 +2090,19 @@ impl Renderer { .map(|(egui_id, delta)| { let size = delta.image.size(); let byte_size = size[0] * size[1] * 4; + let mut staging = buffers::Buffer::new( self.vulkan.device.clone(), - byte_size, - vk::BufferUsageFlags::TRANSFER_SRC, - &[], - vk_mem::MemoryUsage::AutoPreferHost, - vk_mem::AllocationCreateFlags::MAPPED - | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE - | vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT, - Some(format!("egui-{egui_id:?}-staging-buf").into()), + 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"); { @@ -2327,13 +2339,16 @@ impl Renderer { let mut staging = buffers::Buffer::new( device.clone(), - staging_size, - vk::BufferUsageFlags::TRANSFER_SRC, - &[device.queue_families().graphics_familty()], - vk_mem::MemoryUsage::AutoPreferHost, - vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE - | vk_mem::AllocationCreateFlags::MAPPED, - Some("egui-draw-staging".into()), + 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() + }, )?; { @@ -2348,30 +2363,34 @@ impl Renderer { let vertices = buffers::Buffer::new( device.clone(), - vertices_size, - vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, - &[device.queue_families().graphics_familty()], - vk_mem::MemoryUsage::AutoPreferDevice, - vk_mem::AllocationCreateFlags::empty(), - Some("egui-draw-vertices".into()), + 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(), - indices_size, - vk::BufferUsageFlags::INDEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, - &[device.queue_families().graphics_familty()], - vk_mem::MemoryUsage::AutoPreferDevice, - vk_mem::AllocationCreateFlags::empty(), - Some("egui-draw-indices".into()), + 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(), - draw_calls_size, - vk::BufferUsageFlags::INDIRECT_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, - &[device.queue_families().graphics_familty()], - vk_mem::MemoryUsage::AutoPreferDevice, - vk_mem::AllocationCreateFlags::empty(), - Some("egui-draw-draw_calls".into()), + 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( @@ -2404,12 +2423,14 @@ impl Renderer { let mut texture_ids = buffers::Buffer::new( device.clone(), - textures_indices.len() * size_of::(), - vk::BufferUsageFlags::STORAGE_BUFFER, - &[device.queue_families().graphics_familty()], - vk_mem::MemoryUsage::AutoPreferDevice, - vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE, - Some("egui-draw-texture_ids".into()), + 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_arc()?; @@ -3291,7 +3312,6 @@ mod test_swapchain { let surface = Arc::new(Surface::headless(vk.instance.clone())?); let swapchain = Arc::new(Swapchain::new( - vk.instance.clone(), vk.device.clone(), surface.clone(), vk.device.phy(), diff --git a/crates/renderer/src/util.rs b/crates/renderer/src/util.rs index e3636a7..ddeee64 100644 --- a/crates/renderer/src/util.rs +++ b/crates/renderer/src/util.rs @@ -4,9 +4,9 @@ use ash::vk; #[macro_export] macro_rules! def_monotonic_id { - ($ty:ident) => { + ($vis:vis $ty:ident) => { #[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)] - pub struct $ty(::core::num::NonZero); + $vis struct $ty(::core::num::NonZero); impl $ty { pub fn new() -> Self { @@ -331,3 +331,31 @@ pub fn timed T>(label: &str, f: F) -> T { out } + +#[derive(Debug, Clone, Copy)] +pub struct Rgba(pub [f32; 4]); + +impl std::hash::Hash for Rgba { + fn hash(&self, state: &mut H) { + self.0.map(|f| hash_f32(state, f)); + } +} + +#[allow(dead_code)] +impl Rgba { + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { + Self([r, g, b, a]) + } + pub fn into_u32(&self) -> [u32; 4] { + self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u32) + } + pub fn into_f32(&self) -> [f32; 4] { + self.0 + } + pub fn into_snorm(&self) -> [f32; 4] { + self.0.map(|f| (f - 0.5) * 2.0) + } + pub fn into_i32(&self) -> [i32; 4] { + self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as i32 - 128) + } +}