merge Texture and Image structs, add image aliasing

This commit is contained in:
Janis 2025-01-04 02:15:37 +01:00
parent e76055860d
commit 0627556051
2 changed files with 163 additions and 56 deletions

View file

@ -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<vk_mem::Allocation>,
size: vk::Extent3D,
format: vk::Format,
views: Mutex<HashMap<ImageViewDesc, vk::ImageView>>,
aliased: Option<Arc<Image>>,
} => |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<ImageView> {
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<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;
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<vk::ImageView> {
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<ImageView> {
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);

View file

@ -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<Image>,
views: Mutex<HashMap<crate::images::ImageViewDesc, Arc<ImageView>>>,
}
impl Texture {
pub fn id(&self) -> TextureId {
self.id
}
pub fn image(&self) -> Arc<Image> {
self.image.clone()
}
pub fn view(&self, desc: crate::images::ImageViewDesc) -> VkResult<Arc<ImageView>> {
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<TextureId, Arc<Texture>>,
pub textures: BTreeMap<TextureId, Arc<Image>>,
#[allow(unused)]
dev: Device,
}
@ -104,22 +67,20 @@ mod texture {
}
}
pub fn insert_image(&mut self, image: Arc<Image>) -> TextureId {
let id = TextureId::new();
self.textures.insert(id, image);
id
}
pub fn insert_image_with_id(&mut self, id: TextureId, image: Arc<Image>) {
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<Arc<Texture>> {
pub fn remove_texture(&mut self, id: TextureId) -> Option<Arc<Image>> {
self.textures.remove(&id)
}
pub fn get_texture(&self, id: TextureId) -> Option<Arc<Texture>> {
pub fn get_texture(&self, id: TextureId) -> Option<Arc<Image>> {
self.textures.get(&id).cloned()
}
}