From 32ce6e9140ee9065980a30e4a83aa4d0a78fab2c Mon Sep 17 00:00:00 2001
From: Janis <janis@nirgendwo.xyz>
Date: Sat, 4 Jan 2025 02:28:51 +0100
Subject: [PATCH] aliases stored along side views in-line

---
 crates/renderer/src/images.rs       | 188 ++++++++++++++++++----------
 crates/renderer/src/render_graph.rs |   4 +-
 2 files changed, 126 insertions(+), 66 deletions(-)

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<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.
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<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(),
                                     ),