use std::ops::Deref;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use anyhow::Result;
use ash::vk;
use ash::vk::Handle;
use crate::core::traits::{AsRaw, Nameable};
use crate::{Allocation, Allocator, DefaultAllocator, Device, MemoryType};
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Image<A: Allocator = DefaultAllocator> {
#[derivative(Debug = "ignore")]
device: Device,
handle: vk::Image,
#[derivative(Debug = "ignore")]
memory: Option<A::Allocation>,
format: vk::Format,
size: vk::Extent3D,
layers: u32,
mip_levels: u32,
samples: vk::SampleCountFlags,
}
unsafe impl<A: Allocator> Send for Image<A> {}
unsafe impl<A: Allocator> Sync for Image<A> {}
#[derive(Derivative)]
#[derivative(Debug, Hash, PartialEq, Eq)]
pub struct ImgView {
#[derivative(Debug = "ignore")]
#[derivative(Hash = "ignore")]
#[derivative(PartialEq = "ignore")]
device: Device,
handle: vk::ImageView,
image: vk::Image,
format: vk::Format,
samples: vk::SampleCountFlags,
aspect: vk::ImageAspectFlags,
size: vk::Extent3D,
base_level: u32,
level_count: u32,
base_layer: u32,
layer_count: u32,
id: u64,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ImageView(pub Arc<ImgView>);
impl Deref for ImageView {
type Target = Arc<ImgView>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
unsafe impl Send for ImageView {}
unsafe impl Sync for ImageView {}
impl<A: Allocator> Image<A> {
pub fn new(
device: Device,
alloc: &mut A,
width: u32,
height: u32,
usage: vk::ImageUsageFlags,
format: vk::Format,
samples: vk::SampleCountFlags,
) -> Result<Self> {
let sharing_mode = if device.is_single_queue()
|| usage.intersects(
vk::ImageUsageFlags::COLOR_ATTACHMENT
| vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
) {
vk::SharingMode::EXCLUSIVE
} else {
vk::SharingMode::CONCURRENT
};
let handle = unsafe {
device.create_image(
&vk::ImageCreateInfo {
s_type: vk::StructureType::IMAGE_CREATE_INFO,
p_next: std::ptr::null(),
flags: Default::default(),
image_type: vk::ImageType::TYPE_2D,
format,
extent: vk::Extent3D {
width,
height,
depth: 1,
},
mip_levels: 1,
array_layers: 1,
samples,
tiling: vk::ImageTiling::OPTIMAL,
usage,
sharing_mode,
queue_family_index_count: if sharing_mode == vk::SharingMode::CONCURRENT {
device.queue_families().len() as u32
} else {
0
},
p_queue_family_indices: if sharing_mode == vk::SharingMode::CONCURRENT {
device.queue_families().as_ptr()
} else {
std::ptr::null()
},
initial_layout: vk::ImageLayout::UNDEFINED,
},
None,
)?
};
#[cfg(feature = "log-objects")]
trace!("Created new VkImage {handle:p}");
let requirements = unsafe { device.get_image_memory_requirements(handle) };
let memory = alloc.allocate("image_", &requirements, MemoryType::GpuOnly)?;
unsafe {
device.bind_image_memory(handle, memory.memory(), memory.offset())?;
}
Ok(Self {
device,
handle,
format,
size: vk::Extent3D {
width,
height,
depth: 1,
},
layers: 1,
mip_levels: 1,
samples,
memory: Some(memory),
})
}
pub(crate) fn new_managed(
device: Device,
handle: vk::Image,
format: vk::Format,
size: vk::Extent3D,
layers: u32,
mip_levels: u32,
samples: vk::SampleCountFlags,
) -> Self {
Self {
device,
handle,
memory: None,
format,
size,
layers,
mip_levels,
samples,
}
}
pub fn view(&self, aspect: vk::ImageAspectFlags) -> Result<ImageView> {
let info = vk::ImageViewCreateInfo {
s_type: vk::StructureType::IMAGE_VIEW_CREATE_INFO,
p_next: std::ptr::null(),
flags: Default::default(),
image: self.handle,
view_type: vk::ImageViewType::TYPE_2D, format: self.format,
components: vk::ComponentMapping::default(),
subresource_range: vk::ImageSubresourceRange {
aspect_mask: aspect,
base_mip_level: 0,
level_count: self.mip_levels,
base_array_layer: 0,
layer_count: self.layers,
},
};
let view_handle = unsafe { self.device.create_image_view(&info, None)? };
#[cfg(feature = "log-objects")]
trace!("Created new VkImageView {view_handle:p}");
Ok(ImageView(Arc::new(ImgView {
device: self.device.clone(),
handle: view_handle,
image: self.handle,
format: self.format,
samples: self.samples,
aspect,
size: self.size,
base_level: 0,
level_count: self.mip_levels,
base_layer: 0,
layer_count: self.layers,
id: ImgView::get_new_id(),
})))
}
pub fn is_owned(&self) -> bool {
self.memory.is_some()
}
pub unsafe fn handle(&self) -> vk::Image {
self.handle
}
pub fn format(&self) -> vk::Format {
self.format
}
pub fn size(&self) -> vk::Extent3D {
self.size
}
pub fn width(&self) -> u32 {
self.size().width
}
pub fn height(&self) -> u32 {
self.size().height
}
pub fn depth(&self) -> u32 {
self.size().depth
}
pub fn layers(&self) -> u32 {
self.layers
}
pub fn mip_levels(&self) -> u32 {
self.mip_levels
}
pub fn samples(&self) -> vk::SampleCountFlags {
self.samples
}
}
unsafe impl AsRaw for Image {
unsafe fn as_raw(&self) -> u64 {
self.handle().as_raw()
}
}
impl Nameable for Image {
const OBJECT_TYPE: vk::ObjectType = vk::ObjectType::IMAGE;
}
impl<A: Allocator> Drop for Image<A> {
fn drop(&mut self) {
#[cfg(feature = "log-objects")]
trace!("Destroying VkImage {:p}", self.handle);
if self.is_owned() {
unsafe {
self.device.destroy_image(self.handle, None);
}
}
}
}
impl ImgView {
fn get_new_id() -> u64 {
static COUNTER: AtomicU64 = AtomicU64::new(1);
COUNTER.fetch_add(1, Ordering::Relaxed)
}
pub fn subresource_range(&self) -> vk::ImageSubresourceRange {
vk::ImageSubresourceRange {
aspect_mask: self.aspect,
base_mip_level: self.base_level,
level_count: self.level_count,
base_array_layer: self.base_layer,
layer_count: self.layer_count,
}
}
pub unsafe fn handle(&self) -> vk::ImageView {
self.handle
}
pub unsafe fn image(&self) -> vk::Image {
self.image
}
pub fn format(&self) -> vk::Format {
self.format
}
pub fn samples(&self) -> vk::SampleCountFlags {
self.samples
}
pub fn aspect(&self) -> vk::ImageAspectFlags {
self.aspect
}
pub fn size(&self) -> vk::Extent3D {
self.size
}
pub fn width(&self) -> u32 {
self.size().width
}
pub fn height(&self) -> u32 {
self.size().height
}
pub fn depth(&self) -> u32 {
self.size().depth
}
pub fn base_layer(&self) -> u32 {
self.base_layer
}
pub fn layer_count(&self) -> u32 {
self.layer_count
}
pub fn base_level(&self) -> u32 {
self.base_level
}
pub fn level_count(&self) -> u32 {
self.level_count
}
pub fn id(&self) -> u64 {
self.id
}
}
impl Drop for ImgView {
fn drop(&mut self) {
#[cfg(feature = "log-objects")]
trace!("Destroying VkImageView {:p}", self.handle);
unsafe {
self.device.destroy_image_view(self.handle, None);
}
}
}