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::{
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<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! {
#[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<std::borrow::Cow<'static, str>>,
) -> VkResult<Arc<Self>> {
pub fn new(device: Device, desc: BufferDesc) -> VkResult<Arc<Self>> {
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,
)?))
}

View file

@ -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<Instance> {
&self.0.instance
}
pub fn swapchain(&self) -> &khr::swapchain::Device {
&self.0.swapchain
}

View file

@ -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<Cow<'static, str>>,
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);

View file

@ -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<Instance>,
// has a strong ref to the surface because the surface may not outlive the swapchain
surface: Arc<Surface>,
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<Instance>,
device: Device,
surface: Arc<Surface>,
pdev: vk::PhysicalDevice,
extent: vk::Extent2D,
) -> Result<Self> {
Self::create(instance, device, surface, pdev, Some(extent), None)
Self::create(device, surface, pdev, Some(extent), None)
}
fn create(
instance: Arc<Instance>,
device: Device,
surface: Arc<Surface>,
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<vk::Extent2D>) -> Result<Self> {
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<Instance>) -> Result<Self> {
@ -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<W> Renderer<W> {
.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<W> Renderer<W> {
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<W> Renderer<W> {
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<W> Renderer<W> {
let mut texture_ids = buffers::Buffer::new(
device.clone(),
textures_indices.len() * size_of::<u32>(),
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::<u32>()) 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(),

View file

@ -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<u32>);
$vis struct $ty(::core::num::NonZero<u32>);
impl $ty {
pub fn new() -> Self {
@ -331,3 +331,31 @@ pub fn timed<T, F: FnOnce() -> 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<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)
}
}