diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index dd39e77..8295fb2 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -30,6 +30,45 @@ pub struct ImageDesc { pub alloc_flags: vk_mem::AllocationCreateFlags, } +impl std::hash::Hash for ImageDesc { + fn hash(&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>, - aliased: Option>, + aliases: Mutex>>, + parent: Option>, } => |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) -> Arc { + 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, desc: ImageDesc) -> VkResult { - 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, desc: ImageDesc) -> VkResult> { + 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, desc: ImageDesc) -> VkResult> { + 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. diff --git a/crates/renderer/src/render_graph.rs b/crates/renderer/src/render_graph.rs index 7b5bf12..4d7efe0 100644 --- a/crates/renderer/src/render_graph.rs +++ b/crates/renderer/src/render_graph.rs @@ -81,7 +81,7 @@ pub struct EguiPrePass { BTreeMap, staging_image: Arc, staging_buffer: Arc, - aliased_images: BTreeMap, + aliased_images: BTreeMap)>, tessellated: Vec, texture_data: BTreeMap, } @@ -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(), ),