buffer/image desc; queueflags

This commit is contained in:
Janis 2025-01-03 00:21:00 +01:00
parent e3db023ec4
commit da0befbeaf
5 changed files with 225 additions and 86 deletions

View file

@ -1,12 +1,67 @@
use std::{ use std::{
borrow::Cow,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::Arc, sync::Arc,
}; };
use ash::{prelude::VkResult, vk}; use ash::{prelude::VkResult, vk};
use itertools::Itertools;
use vk_mem::Alloc; 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<Cow<'static, str>>,
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! { define_device_owned_handle! {
#[derive(Debug)] #[derive(Debug)]
@ -19,15 +74,9 @@ define_device_owned_handle! {
} }
impl Buffer { impl Buffer {
pub fn new( pub fn new(device: Device, desc: BufferDesc) -> VkResult<Arc<Self>> {
device: Device, let queue_families = device.queue_families().family_indices(desc.queue_families);
size: usize,
usage: vk::BufferUsageFlags,
queue_families: &[u32],
memory_usage: vk_mem::MemoryUsage,
alloc_flags: vk_mem::AllocationCreateFlags,
name: Option<std::borrow::Cow<'static, str>>,
) -> VkResult<Arc<Self>> {
let sharing_mode = if queue_families.len() > 1 { let sharing_mode = if queue_families.len() > 1 {
vk::SharingMode::CONCURRENT vk::SharingMode::CONCURRENT
} else { } else {
@ -37,24 +86,20 @@ impl Buffer {
let (buffer, allocation) = unsafe { let (buffer, allocation) = unsafe {
device.alloc().create_buffer( device.alloc().create_buffer(
&vk::BufferCreateInfo::default() &vk::BufferCreateInfo::default()
.size(size as u64) .size(desc.size)
.usage(usage) .usage(desc.usage)
.queue_family_indices(queue_families) .queue_family_indices(&queue_families)
.sharing_mode(sharing_mode), .sharing_mode(sharing_mode),
&vk_mem::AllocationCreateInfo { &vk_mem::AllocationCreateInfo {
flags: alloc_flags, flags: desc.alloc_flags,
usage: memory_usage, usage: desc.mem_usage,
..Default::default() ..Default::default()
}, },
)? )?
}; };
Ok(Arc::new(Self::construct( Ok(Arc::new(Self::construct(
device, device, buffer, desc.name, allocation, desc.size,
buffer,
name,
allocation,
size as u64,
)?)) )?))
} }

View file

@ -40,6 +40,41 @@ impl DeviceQueueFamilies {
pub fn transfer_familty(&self) -> u32 { pub fn transfer_familty(&self) -> u32 {
self.transfer.0 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)] #[repr(transparent)]
@ -186,6 +221,9 @@ impl Device {
pub fn dev(&self) -> &ash::Device { pub fn dev(&self) -> &ash::Device {
&self.0.device &self.0.device
} }
pub fn instance(&self) -> &Arc<Instance> {
&self.0.instance
}
pub fn swapchain(&self) -> &khr::swapchain::Device { pub fn swapchain(&self) -> &khr::swapchain::Device {
&self.0.swapchain &self.0.swapchain
} }

View file

@ -1,6 +1,9 @@
use std::borrow::Cow; 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 super::Device;
use ash::{prelude::*, vk}; use ash::{prelude::*, vk};
@ -8,7 +11,7 @@ use itertools::Itertools;
use vk_mem::Alloc; use vk_mem::Alloc;
#[derive(Clone)] #[derive(Clone)]
pub struct ImageDesc<'a> { pub struct ImageDesc {
pub flags: vk::ImageCreateFlags, pub flags: vk::ImageCreateFlags,
pub name: Option<Cow<'static, str>>, pub name: Option<Cow<'static, str>>,
pub format: vk::Format, pub format: vk::Format,
@ -19,14 +22,14 @@ pub struct ImageDesc<'a> {
pub extent: vk::Extent3D, pub extent: vk::Extent3D,
pub tiling: vk::ImageTiling, pub tiling: vk::ImageTiling,
pub usage: vk::ImageUsageFlags, pub usage: vk::ImageUsageFlags,
pub queue_families: &'a [u32], pub queue_families: QueueFlags,
pub layout: vk::ImageLayout, pub layout: vk::ImageLayout,
pub mem_usage: vk_mem::MemoryUsage, pub mem_usage: vk_mem::MemoryUsage,
pub alloc_flags: vk_mem::AllocationCreateFlags, 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImageDesc") f.debug_struct("ImageDesc")
.field("flags", &self.flags) .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 { fn default() -> Self {
Self { Self {
flags: Default::default(), flags: Default::default(),
@ -69,7 +72,7 @@ impl<'a> Default for ImageDesc<'a> {
extent: Default::default(), extent: Default::default(),
tiling: vk::ImageTiling::OPTIMAL, tiling: vk::ImageTiling::OPTIMAL,
usage: Default::default(), usage: Default::default(),
queue_families: &[], queue_families: QueueFlags::empty(),
layout: vk::ImageLayout::UNDEFINED, layout: vk::ImageLayout::UNDEFINED,
alloc_flags: vk_mem::AllocationCreateFlags::empty(), alloc_flags: vk_mem::AllocationCreateFlags::empty(),
mem_usage: vk_mem::MemoryUsage::Auto, mem_usage: vk_mem::MemoryUsage::Auto,
@ -106,6 +109,15 @@ impl Image {
mem_usage, mem_usage,
alloc_flags, alloc_flags,
} = desc; } = 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() let info = &vk::ImageCreateInfo::default()
.flags(flags) .flags(flags)
.image_type(kind) .image_type(kind)
@ -115,12 +127,8 @@ impl Image {
.initial_layout(layout) .initial_layout(layout)
.tiling(tiling) .tiling(tiling)
.usage(usage) .usage(usage)
.sharing_mode(if queue_families.len() > 1 { .sharing_mode(sharing_mode)
vk::SharingMode::CONCURRENT .queue_family_indices(&queue_families)
} else {
vk::SharingMode::EXCLUSIVE
})
.queue_family_indices(queue_families)
.array_layers(array_layers) .array_layers(array_layers)
.mip_levels(mip_levels); .mip_levels(mip_levels);

View file

@ -4,7 +4,8 @@
let_chains, let_chains,
negative_impls, negative_impls,
map_try_insert, map_try_insert,
debug_closure_helpers debug_closure_helpers,
slice_partition_dedup
)] )]
use std::{ use std::{
@ -18,7 +19,6 @@ use std::{
atomic::{AtomicU32, AtomicU64}, atomic::{AtomicU32, AtomicU64},
Arc, Arc,
}, },
time::Instant,
}; };
use egui::Color32; use egui::Color32;
@ -61,7 +61,7 @@ mod texture {
Device, Device,
}; };
def_monotonic_id!(TextureId); def_monotonic_id!(pub TextureId);
pub struct Texture { pub struct Texture {
id: TextureId, id: TextureId,
@ -125,7 +125,7 @@ mod texture {
} }
} }
use render_graph::Rgba; use util::Rgba;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
@ -526,9 +526,9 @@ impl SwapchainHandle {
} }
} }
#[derive(Debug)]
pub struct Swapchain { pub struct Swapchain {
device: Device, device: Device,
instance: Arc<Instance>,
// has a strong ref to the surface because the surface may not outlive the swapchain // has a strong ref to the surface because the surface may not outlive the swapchain
surface: Arc<Surface>, surface: Arc<Surface>,
swapchain: SwapchainHandle, swapchain: SwapchainHandle,
@ -610,6 +610,7 @@ struct SwapchainParams {
extent: vk::Extent2D, extent: vk::Extent2D,
} }
#[derive(Debug)]
#[must_use = "This struct represents an acquired image from the swapchain and #[must_use = "This struct represents an acquired image from the swapchain and
must be presented in order to free resources on the device."] must be presented in order to free resources on the device."]
pub struct SwapchainFrame { pub struct SwapchainFrame {
@ -696,17 +697,15 @@ impl Swapchain {
} }
pub fn new( pub fn new(
instance: Arc<Instance>,
device: Device, device: Device,
surface: Arc<Surface>, surface: Arc<Surface>,
pdev: vk::PhysicalDevice, pdev: vk::PhysicalDevice,
extent: vk::Extent2D, extent: vk::Extent2D,
) -> Result<Self> { ) -> Result<Self> {
Self::create(instance, device, surface, pdev, Some(extent), None) Self::create(device, surface, pdev, Some(extent), None)
} }
fn create( fn create(
instance: Arc<Instance>,
device: Device, device: Device,
surface: Arc<Surface>, surface: Arc<Surface>,
pdev: vk::PhysicalDevice, pdev: vk::PhysicalDevice,
@ -720,7 +719,12 @@ impl Swapchain {
image_count, image_count,
min_image_count, min_image_count,
extent, 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 (swapchain, images) = {
let lock = old_swapchain.as_ref().map(|handle| handle.lock()); let lock = old_swapchain.as_ref().map(|handle| handle.lock());
@ -841,7 +845,6 @@ impl Swapchain {
tracing::debug!("fences: {fences:?}"); tracing::debug!("fences: {fences:?}");
Ok(Self { Ok(Self {
instance,
device, device,
surface, surface,
swapchain, swapchain,
@ -870,7 +873,6 @@ impl Swapchain {
fn recreate(&self, extent: Option<vk::Extent2D>) -> Result<Self> { fn recreate(&self, extent: Option<vk::Extent2D>) -> Result<Self> {
Self::create( Self::create(
self.instance.clone(),
self.device.clone(), self.device.clone(),
self.surface.clone(), self.surface.clone(),
self.device.phy(), self.device.phy(),
@ -1035,6 +1037,14 @@ pub struct Surface {
surface: vk::SurfaceKHR, 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 { impl Surface {
#[allow(dead_code)] #[allow(dead_code)]
fn headless(instance: Arc<Instance>) -> Result<Self> { fn headless(instance: Arc<Instance>) -> Result<Self> {
@ -1734,7 +1744,6 @@ impl WindowContext {
let surface = Arc::new(Surface::create(instance.clone(), display, window_handle)?); let surface = Arc::new(Surface::create(instance.clone(), display, window_handle)?);
let swapchain = Arc::new(Swapchain::new( let swapchain = Arc::new(Swapchain::new(
instance,
device.clone(), device.clone(),
surface.clone(), surface.clone(),
device.phy(), device.phy(),
@ -2081,16 +2090,19 @@ impl<W> Renderer<W> {
.map(|(egui_id, delta)| { .map(|(egui_id, delta)| {
let size = delta.image.size(); let size = delta.image.size();
let byte_size = size[0] * size[1] * 4; let byte_size = size[0] * size[1] * 4;
let mut staging = buffers::Buffer::new( let mut staging = buffers::Buffer::new(
self.vulkan.device.clone(), self.vulkan.device.clone(),
byte_size, buffers::BufferDesc {
vk::BufferUsageFlags::TRANSFER_SRC, name: Some(format!("egui-{egui_id:?}-staging-buf").into()),
&[], size: byte_size as u64,
vk_mem::MemoryUsage::AutoPreferHost, usage: vk::BufferUsageFlags::TRANSFER_SRC,
vk_mem::AllocationCreateFlags::MAPPED mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT, | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
Some(format!("egui-{egui_id:?}-staging-buf").into()), | vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
..Default::default()
},
) )
.expect("staging buffer"); .expect("staging buffer");
{ {
@ -2327,13 +2339,16 @@ impl<W> Renderer<W> {
let mut staging = buffers::Buffer::new( let mut staging = buffers::Buffer::new(
device.clone(), device.clone(),
staging_size, buffers::BufferDesc {
vk::BufferUsageFlags::TRANSFER_SRC, name: Some("egui-draw-staging".into()),
&[device.queue_families().graphics_familty()], size: staging_size as u64,
vk_mem::MemoryUsage::AutoPreferHost, usage: vk::BufferUsageFlags::TRANSFER_SRC,
vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
| vk_mem::AllocationCreateFlags::MAPPED, alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
Some("egui-draw-staging".into()), | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
..Default::default()
},
)?; )?;
{ {
@ -2348,30 +2363,34 @@ impl<W> Renderer<W> {
let vertices = buffers::Buffer::new( let vertices = buffers::Buffer::new(
device.clone(), device.clone(),
vertices_size, buffers::BufferDesc {
vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, name: Some("egui-draw-vertices".into()),
&[device.queue_families().graphics_familty()], size: vertices_size as u64,
vk_mem::MemoryUsage::AutoPreferDevice, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
vk_mem::AllocationCreateFlags::empty(), mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
Some("egui-draw-vertices".into()), ..Default::default()
},
)?; )?;
let indices = buffers::Buffer::new( let indices = buffers::Buffer::new(
device.clone(), device.clone(),
indices_size, buffers::BufferDesc {
vk::BufferUsageFlags::INDEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, name: Some("egui-draw-indices".into()),
&[device.queue_families().graphics_familty()], size: indices_size as u64,
vk_mem::MemoryUsage::AutoPreferDevice, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER,
vk_mem::AllocationCreateFlags::empty(), mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
Some("egui-draw-indices".into()), ..Default::default()
},
)?; )?;
let draw_calls = buffers::Buffer::new( let draw_calls = buffers::Buffer::new(
device.clone(), device.clone(),
draw_calls_size, buffers::BufferDesc {
vk::BufferUsageFlags::INDIRECT_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, name: Some("egui-draw-draw_calls".into()),
&[device.queue_families().graphics_familty()], size: draw_calls_size as u64,
vk_mem::MemoryUsage::AutoPreferDevice, usage: vk::BufferUsageFlags::TRANSFER_DST
vk_mem::AllocationCreateFlags::empty(), | vk::BufferUsageFlags::INDIRECT_BUFFER,
Some("egui-draw-draw_calls".into()), mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default()
},
)?; )?;
cmd.copy_buffers( cmd.copy_buffers(
@ -2404,12 +2423,14 @@ impl<W> Renderer<W> {
let mut texture_ids = buffers::Buffer::new( let mut texture_ids = buffers::Buffer::new(
device.clone(), device.clone(),
textures_indices.len() * size_of::<u32>(), buffers::BufferDesc {
vk::BufferUsageFlags::STORAGE_BUFFER, name: Some("egui-draw-texture_ids".into()),
&[device.queue_families().graphics_familty()], size: (textures_indices.len() * size_of::<u32>()) as u64,
vk_mem::MemoryUsage::AutoPreferDevice, usage: vk::BufferUsageFlags::STORAGE_BUFFER,
vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
Some("egui-draw-texture_ids".into()), alloc_flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
..Default::default()
},
)?; )?;
{ {
let mut map = texture_ids.map_arc()?; let mut map = texture_ids.map_arc()?;
@ -3291,7 +3312,6 @@ mod test_swapchain {
let surface = Arc::new(Surface::headless(vk.instance.clone())?); let surface = Arc::new(Surface::headless(vk.instance.clone())?);
let swapchain = Arc::new(Swapchain::new( let swapchain = Arc::new(Swapchain::new(
vk.instance.clone(),
vk.device.clone(), vk.device.clone(),
surface.clone(), surface.clone(),
vk.device.phy(), vk.device.phy(),

View file

@ -4,9 +4,9 @@ use ash::vk;
#[macro_export] #[macro_export]
macro_rules! def_monotonic_id { macro_rules! def_monotonic_id {
($ty:ident) => { ($vis:vis $ty:ident) => {
#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)] #[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct $ty(::core::num::NonZero<u32>); $vis struct $ty(::core::num::NonZero<u32>);
impl $ty { impl $ty {
pub fn new() -> Self { pub fn new() -> Self {
@ -331,3 +331,31 @@ pub fn timed<T, F: FnOnce() -> T>(label: &str, f: F) -> T {
out out
} }
#[derive(Debug, Clone, Copy)]
pub struct Rgba(pub [f32; 4]);
impl std::hash::Hash for Rgba {
fn hash<H: std::hash::Hasher>(&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)
}
}