From 06275560512338530066317bc53b6413962962a5 Mon Sep 17 00:00:00 2001 From: Janis Date: Sat, 4 Jan 2025 02:15:37 +0100 Subject: [PATCH] merge Texture and Image structs, add image aliasing --- crates/renderer/src/images.rs | 158 ++++++++++++++++++++++++++++++++-- crates/renderer/src/lib.rs | 61 +++---------- 2 files changed, 163 insertions(+), 56 deletions(-) diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index 345e943..dd39e77 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -1,13 +1,14 @@ -use std::borrow::Cow; +use std::{borrow::Cow, collections::HashMap, sync::Arc}; use crate::{ define_device_owned_handle, - device::{DeviceOwned, QueueFlags}, + device::{self, DeviceOwned, QueueFlags}, }; use super::Device; use ash::{prelude::*, vk}; use itertools::Itertools; +use parking_lot::Mutex; use vk_mem::Alloc; #[derive(Clone)] @@ -83,11 +84,18 @@ impl Default for ImageDesc { define_device_owned_handle! { #[derive(Debug)] pub Image(vk::Image) { - alloc: vk_mem::Allocation, + alloc: Option, size: vk::Extent3D, format: vk::Format, + views: Mutex>, + aliased: Option>, } => |this| unsafe { - this.inner.dev().alloc().destroy_image(this.handle(), &mut this.alloc); + for &view in this.views.lock().values() { + this.inner.dev().dev().destroy_image_view(view, None); + } + if this.aliased.is_none() { + this.inner.dev().alloc().destroy_image(this.handle(), this.alloc.as_mut().unwrap()); + } } } @@ -140,7 +148,16 @@ impl Image { let (handle, alloc) = unsafe { device.alloc().create_image(info, alloc_info)? }; - Self::construct(device, handle, name, alloc, extent, format) + Self::construct( + device, + handle, + name, + Some(alloc), + extent, + format, + Mutex::new(HashMap::new()), + None, + ) } pub fn format(&self) -> vk::Format { @@ -168,7 +185,110 @@ impl Image { self.size.depth } - pub fn view(&self, desc: ImageViewDesc) -> VkResult { + fn get_alloc(&self) -> Option<&vk_mem::Allocation> { + self.alloc + .as_ref() + .or(self.aliased.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; + + let queue_families = self + .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) + .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 alloc = self.get_alloc().unwrap(); + + 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 + }; + + 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. + pub fn get_view(&self, desc: ImageViewDesc) -> VkResult { + use std::collections::hash_map::Entry::*; + match self.views.lock().entry(desc.hash_eq_copy()) { + Occupied(occupied) => Ok(*occupied.get()), + Vacant(vacant) => { + let view = unsafe { + let create_info = vk::ImageViewCreateInfo::default() + .flags(desc.flags) + .image(self.image()) + .view_type(vk::ImageViewType::TYPE_2D) + .format(desc.format) + .components(desc.components) + .subresource_range( + vk::ImageSubresourceRange::default() + .aspect_mask(desc.aspect) + .base_mip_level(desc.mip_range.0) + .level_count(desc.mip_range.count()) + .base_array_layer(desc.layer_range.0) + .layer_count(desc.layer_range.count()), + ); + self.device().dev().create_image_view(&create_info, None)? + }; + Ok(*vacant.insert(view)) + } + } + } + + pub fn create_view(&self, desc: ImageViewDesc) -> VkResult { let create_info = vk::ImageViewCreateInfo::default() .flags(desc.flags) .image(self.image()) @@ -202,6 +322,32 @@ pub struct ImageViewDesc { pub layer_range: MipRange, } +impl ImageViewDesc { + pub fn hash_eq_copy(&self) -> Self { + let &Self { + flags, + kind, + format, + components, + aspect, + mip_range, + layer_range, + .. + } = self; + + Self { + flags, + name: None, + kind, + format, + components, + aspect, + mip_range, + layer_range, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MipRange(u32, u32); diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 9d89579..42884a5 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -47,51 +47,14 @@ mod util; use device::{Device, DeviceOwned, DeviceQueueFamilies}; mod texture { - use std::{ - collections::{hash_map::Entry, BTreeMap, HashMap}, - sync::Arc, - }; + use std::{collections::BTreeMap, sync::Arc}; - use ash::prelude::VkResult; - use parking_lot::Mutex; - - use crate::{ - def_monotonic_id, - images::{Image, ImageView}, - Device, - }; + use crate::{def_monotonic_id, images::Image, Device}; def_monotonic_id!(pub TextureId); - pub struct Texture { - id: TextureId, - image: Arc, - views: Mutex>>, - } - - impl Texture { - pub fn id(&self) -> TextureId { - self.id - } - pub fn image(&self) -> Arc { - self.image.clone() - } - pub fn view(&self, desc: crate::images::ImageViewDesc) -> VkResult> { - let mut views = self.views.lock(); - let view = match views.entry(desc) { - Entry::Occupied(entry) => entry.get().clone(), - Entry::Vacant(entry) => { - let view = Arc::new(self.image.view(entry.key().clone())?); - entry.insert(view).clone() - } - }; - - Ok(view) - } - } - pub struct TextureManager { - pub textures: BTreeMap>, + pub textures: BTreeMap>, #[allow(unused)] dev: Device, } @@ -104,22 +67,20 @@ mod texture { } } + pub fn insert_image(&mut self, image: Arc) -> TextureId { + let id = TextureId::new(); + self.textures.insert(id, image); + id + } pub fn insert_image_with_id(&mut self, id: TextureId, image: Arc) { - self.textures.insert( - id, - Arc::new(Texture { - id, - image, - views: Mutex::new(HashMap::new()), - }), - ); + self.textures.insert(id, image); } - pub fn remove_texture(&mut self, id: TextureId) -> Option> { + pub fn remove_texture(&mut self, id: TextureId) -> Option> { self.textures.remove(&id) } - pub fn get_texture(&self, id: TextureId) -> Option> { + pub fn get_texture(&self, id: TextureId) -> Option> { self.textures.get(&id).cloned() } }