aliases stored along side views in-line

This commit is contained in:
Janis 2025-01-04 02:28:51 +01:00
parent d66071f7bb
commit 32ce6e9140
2 changed files with 126 additions and 66 deletions

View file

@ -30,6 +30,45 @@ pub struct ImageDesc {
pub alloc_flags: vk_mem::AllocationCreateFlags,
}
impl std::hash::Hash for ImageDesc {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.flags.hash(state);
self.name.hash(state);
self.format.hash(state);
self.kind.hash(state);
self.mip_levels.hash(state);
self.array_layers.hash(state);
self.samples.hash(state);
self.extent.hash(state);
self.tiling.hash(state);
self.usage.hash(state);
self.queue_families.hash(state);
self.layout.hash(state);
self.mem_usage.hash(state);
self.alloc_flags.bits().hash(state);
}
}
impl Eq for ImageDesc {}
impl PartialEq for ImageDesc {
fn eq(&self, other: &Self) -> bool {
self.flags == other.flags
&& self.name == other.name
&& self.format == other.format
&& self.kind == other.kind
&& self.mip_levels == other.mip_levels
&& self.array_layers == other.array_layers
&& self.samples == other.samples
&& self.extent == other.extent
&& self.tiling == other.tiling
&& self.usage == other.usage
&& self.queue_families == other.queue_families
&& self.layout == other.layout
&& self.mem_usage == other.mem_usage
&& self.alloc_flags.bits() == other.alloc_flags.bits()
}
}
impl<'a> std::fmt::Debug for ImageDesc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImageDesc")
@ -88,13 +127,18 @@ define_device_owned_handle! {
size: vk::Extent3D,
format: vk::Format,
views: Mutex<HashMap<ImageViewDesc, vk::ImageView>>,
aliased: Option<Arc<Image>>,
aliases: Mutex<HashMap<ImageDesc, Arc<Image>>>,
parent: Option<Arc<Image>>,
} => |this| unsafe {
for &view in this.views.lock().values() {
this.inner.dev().dev().destroy_image_view(view, None);
}
if this.aliased.is_none() {
if this.parent.is_none() {
// destroy image handle and allocation
this.inner.dev().alloc().destroy_image(this.handle(), this.alloc.as_mut().unwrap());
} else {
// destroy image handle
this.inner.dev().dev().destroy_image(this.handle(), None);
}
}
}
@ -156,7 +200,8 @@ impl Image {
extent,
format,
Mutex::new(HashMap::new()),
None,
Mutex::new(HashMap::new()),
None, // aliased
)
}
@ -185,79 +230,94 @@ impl Image {
self.size.depth
}
fn get_parent(self: Arc<Self>) -> Arc<Image> {
self.parent.clone().unwrap_or(self)
}
fn get_alloc(&self) -> Option<&vk_mem::Allocation> {
self.alloc
.as_ref()
.or(self.aliased.as_ref().and_then(|image| image.get_alloc()))
.or(self.parent.as_ref().and_then(|image| image.get_alloc()))
}
pub unsafe fn alias(self: Arc<Self>, desc: ImageDesc) -> VkResult<Image> {
let ImageDesc {
flags,
name,
format,
kind,
mip_levels,
array_layers,
samples,
extent,
tiling,
usage,
queue_families,
layout,
mem_usage,
alloc_flags,
} = desc;
pub unsafe fn get_alias(self: Arc<Self>, desc: ImageDesc) -> VkResult<Arc<Self>> {
self.get_parent().get_alias_inner(desc)
}
let queue_families = self
.device()
.queue_families()
.family_indices(queue_families);
unsafe fn get_alias_inner(self: Arc<Self>, desc: ImageDesc) -> VkResult<Arc<Image>> {
use std::collections::hash_map::Entry::*;
match self.aliases.lock().entry(desc.clone()) {
Occupied(occupied) => Ok(occupied.get().clone()),
Vacant(vacant) => {
let ImageDesc {
flags,
name,
format,
kind,
mip_levels,
array_layers,
samples,
extent,
tiling,
usage,
queue_families,
layout,
..
} = desc;
let sharing_mode = if queue_families.len() > 1 {
vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
};
let queue_families = self
.device()
.queue_families()
.family_indices(queue_families);
let info = &vk::ImageCreateInfo::default()
.flags(flags)
.image_type(kind)
.format(format)
.extent(extent)
.samples(samples)
.initial_layout(layout)
.tiling(tiling)
.usage(usage)
.sharing_mode(sharing_mode)
.queue_family_indices(&queue_families)
.array_layers(array_layers)
.mip_levels(mip_levels);
let sharing_mode = if queue_families.len() > 1 {
vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
};
let alloc = self.get_alloc().unwrap();
let info = &vk::ImageCreateInfo::default()
.flags(flags)
.image_type(kind)
.format(format)
.extent(extent)
.samples(samples)
.initial_layout(layout)
.tiling(tiling)
.usage(usage)
.sharing_mode(sharing_mode)
.queue_family_indices(&queue_families)
.array_layers(array_layers)
.mip_levels(mip_levels);
let image = unsafe {
let image = self.device().dev().create_image(info, None)?;
let alloc = self.get_alloc().unwrap();
let req = self.device().dev().get_image_memory_requirements(image);
if self.device().alloc().get_allocation_info(alloc).size < req.size {
return Err(vk::Result::ERROR_MEMORY_MAP_FAILED);
let image = unsafe {
let image = self.device().dev().create_image(info, None)?;
let req = self.device().dev().get_image_memory_requirements(image);
if self.device().alloc().get_allocation_info(alloc).size < req.size {
return Err(vk::Result::ERROR_MEMORY_MAP_FAILED);
}
self.device().alloc().bind_image_memory(alloc, image)?;
image
};
let alias = Self::construct(
self.device().clone(),
image,
name,
None,
extent,
format,
Mutex::new(HashMap::new()),
Mutex::new(HashMap::new()),
Some(self.parent.clone().unwrap_or(self.clone())),
)?;
Ok(vacant.insert(Arc::new(alias)).clone())
}
self.device().alloc().bind_image_memory(alloc, image)?;
image
};
Self::construct(
self.device().clone(),
image,
name,
None,
extent,
format,
Mutex::new(HashMap::new()),
Some(self.aliased.clone().unwrap_or(self)),
)
}
}
/// technically, this ImageView belongs to the image and is managed by it.

View file

@ -81,7 +81,7 @@ pub struct EguiPrePass {
BTreeMap<egui::TextureId, (RenderGraphResourceId, texture::TextureId, ResourceAccess)>,
staging_image: Arc<Image>,
staging_buffer: Arc<Buffer>,
aliased_images: BTreeMap<egui::TextureId, (usize, usize, [usize; 2], Image)>,
aliased_images: BTreeMap<egui::TextureId, (usize, usize, [usize; 2], Arc<Image>)>,
tessellated: Vec<egui::ClippedPrimitive>,
texture_data: BTreeMap<egui::TextureId, egui::epaint::ImageDelta>,
}
@ -224,7 +224,7 @@ impl EguiPrePass {
unsafe {
let alias = staging_image
.clone()
.alias(ImageDesc {
.get_alias(ImageDesc {
name: Some(
format!("egui-prepass-staging-aliased-{id:?}").into(),
),