use crate::{
error::{SarektError, SarektResult},
image_data::{ImageData, ImageDataFormat},
renderer::config::NumSamples,
};
use log::warn;
use slotmap::{DefaultKey, SlotMap};
use std::{
fmt::Debug,
sync::{Arc, RwLock, Weak},
};
pub struct BufferImageHandle<BL>
where
BL: BufferAndImageLoader,
BL::BackendHandle: BackendHandleTrait + Copy + Debug,
{
inner_key: DefaultKey,
resource_type: ResourceType,
buffer_store: Weak<RwLock<BufferImageStore<BL>>>,
}
impl<BL> Drop for BufferImageHandle<BL>
where
BL: BufferAndImageLoader,
BL::BackendHandle: BackendHandleTrait + Copy + Debug,
{
fn drop(&mut self) {
let buffer_store = self.buffer_store.upgrade();
if matches!(buffer_store, None) {
return;
}
let mut buffer_store_guard = buffer_store
.as_ref()
.unwrap()
.write()
.expect("Could not unlock BufferStore due to previous panic");
let result = match self.resource_type {
ResourceType::Buffer(_) => buffer_store_guard.destroy_buffer(self.inner_key),
ResourceType::Image => buffer_store_guard.destroy_image(self.inner_key),
};
match result {
Err(SarektError::UnknownResource) => {}
Err(e) => warn!(
"resource not destroyed, maybe it was already? Error: {:?}",
e
),
Ok(()) => {}
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum ResourceType {
Image,
Buffer(BufferType),
}
#[derive(Copy, Clone, Debug)]
pub enum BufferType {
Vertex,
Uniform,
Index(IndexBufferElemSize),
}
#[derive(Copy, Clone, Debug)]
pub enum IndexBufferElemSize {
UInt16,
UInt32,
}
pub unsafe trait BackendHandleTrait: Copy {}
#[derive(Clone, Debug)]
pub struct UniformBufferHandle<BL: BufferAndImageLoader, BufElem: Sized + Copy> {
pub uniform_buffer_backend_handle: BL::UniformBufferHandle,
_marker: std::marker::PhantomData<BufElem>,
}
impl<BL: BufferAndImageLoader, BufElem: Sized + Copy> UniformBufferHandle<BL, BufElem> {
pub fn new(uniform_buffer_backend_handle: BL::UniformBufferHandle) -> Self {
Self {
uniform_buffer_backend_handle,
_marker: std::marker::PhantomData,
}
}
}
pub unsafe trait BufferAndImageLoader {
type BackendHandle;
type UniformBufferDataHandle: Debug;
type UniformBufferHandle;
unsafe fn cleanup(&self) -> SarektResult<()>;
fn load_buffer_with_staging<BufElem: Sized + Copy>(
&self, buffer_type: BufferType, buffer: &[BufElem],
) -> SarektResult<Self::BackendHandle>;
fn load_buffer_without_staging<BufElem: Sized + Copy>(
&self, buffer_type: BufferType, buffer: &[BufElem],
) -> SarektResult<Self::BackendHandle>;
fn load_image_with_staging_initialization(
&self, pixels: impl ImageData, magnification_filter: MagnificationMinificationFilter,
minification_filter: MagnificationMinificationFilter, address_x: TextureAddressMode,
address_y: TextureAddressMode, address_z: TextureAddressMode, mip_levels: u32,
) -> SarektResult<Self::BackendHandle>;
fn create_uninitialized_image(
&self, dimensions: (u32, u32), format: ImageDataFormat, num_msaa_samples: NumSamples,
) -> SarektResult<Self::BackendHandle>;
fn delete_buffer_or_image(&self, handle: Self::BackendHandle) -> SarektResult<()>;
}
pub struct BufferImageStore<BL>
where
BL: BufferAndImageLoader,
BL::BackendHandle: BackendHandleTrait + Copy + Debug,
{
loaded_buffers_and_images: SlotMap<DefaultKey, BufferOrImage<BL::BackendHandle>>,
buffer_image_loader: BL,
}
impl<BL> BufferImageStore<BL>
where
BL: BufferAndImageLoader,
BL::BackendHandle: BackendHandleTrait + Copy + Debug,
{
pub fn new(buffer_loader: BL) -> Self {
Self {
loaded_buffers_and_images: SlotMap::new(),
buffer_image_loader: buffer_loader,
}
}
pub unsafe fn cleanup(&mut self) -> SarektResult<()> {
self.buffer_image_loader.cleanup()?;
self.destroy_all_images_and_buffers();
Ok(())
}
pub(crate) fn load_buffer_with_staging<BufElem: Sized + Copy>(
this: &Arc<RwLock<Self>>, buffer_type: BufferType, buffer: &[BufElem],
) -> SarektResult<(BufferImageHandle<BL>, BufferOrImage<BL::BackendHandle>)> {
let mut buffer_store = this
.write()
.expect("Could not unlock BufferStore due to previous panic");
let buffer_backend_handle = buffer_store
.buffer_image_loader
.load_buffer_with_staging(buffer_type, buffer)?;
let buffer_or_image =
BufferOrImage::new(buffer_backend_handle, ResourceType::Buffer(buffer_type));
let inner_key = buffer_store
.loaded_buffers_and_images
.insert(buffer_or_image);
Ok((
BufferImageHandle {
inner_key,
resource_type: ResourceType::Buffer(buffer_type),
buffer_store: Arc::downgrade(this),
},
buffer_or_image,
))
}
pub(crate) fn load_buffer_without_staging<BufElem: Sized + Copy>(
this: &Arc<RwLock<Self>>, buffer_type: BufferType, buffer: &[BufElem],
) -> SarektResult<(BufferImageHandle<BL>, BufferOrImage<BL::BackendHandle>)> {
let mut buffer_store = this
.write()
.expect("Could not unlock BufferStore due to previous panic");
let buffer_backend_handle = buffer_store
.buffer_image_loader
.load_buffer_without_staging(buffer_type, buffer)?;
let buffer_or_image =
BufferOrImage::new(buffer_backend_handle, ResourceType::Buffer(buffer_type));
let inner_key = buffer_store
.loaded_buffers_and_images
.insert(buffer_or_image);
Ok((
BufferImageHandle {
inner_key,
resource_type: ResourceType::Buffer(buffer_type),
buffer_store: Arc::downgrade(this),
},
buffer_or_image,
))
}
fn destroy_buffer(&mut self, inner_key: DefaultKey) -> SarektResult<()> {
let buffer = self.loaded_buffers_and_images.remove(inner_key);
if buffer.is_none() {
return Err(SarektError::UnknownResource);
}
self
.buffer_image_loader
.delete_buffer_or_image(buffer.unwrap().handle)
}
pub(crate) fn load_image_with_staging_initialization(
this: &Arc<RwLock<Self>>, pixels: impl ImageData,
magnification_filter: MagnificationMinificationFilter,
minification_filter: MagnificationMinificationFilter, address_x: TextureAddressMode,
address_y: TextureAddressMode, address_z: TextureAddressMode, mip_levels: u32,
) -> SarektResult<(BufferImageHandle<BL>, BufferOrImage<BL::BackendHandle>)> {
let mut buffer_store = this
.write()
.expect("Could not unlock BufferStore due to previous panic");
let buffer_backend_handle = buffer_store
.buffer_image_loader
.load_image_with_staging_initialization(
pixels,
magnification_filter,
minification_filter,
address_x,
address_y,
address_z,
mip_levels,
)?;
let buffer_or_image = BufferOrImage::new(buffer_backend_handle, ResourceType::Image);
let inner_key = buffer_store
.loaded_buffers_and_images
.insert(buffer_or_image);
Ok((
BufferImageHandle {
inner_key,
resource_type: ResourceType::Image,
buffer_store: Arc::downgrade(this),
},
buffer_or_image,
))
}
pub(crate) fn create_uninitialized_image(
this: &Arc<RwLock<Self>>, dimensions: (u32, u32), format: ImageDataFormat,
) -> SarektResult<(BufferImageHandle<BL>, BufferOrImage<BL::BackendHandle>)> {
Self::create_uninitialized_image_msaa(this, dimensions, format, NumSamples::One)
}
pub(crate) fn create_uninitialized_image_msaa(
this: &Arc<RwLock<Self>>, dimensions: (u32, u32), format: ImageDataFormat,
num_msaa_samples: NumSamples,
) -> SarektResult<(BufferImageHandle<BL>, BufferOrImage<BL::BackendHandle>)> {
let mut buffer_store = this
.write()
.expect("Could not unlock BufferStore due to previous panic");
let buffer_backend_handle = buffer_store
.buffer_image_loader
.create_uninitialized_image(dimensions, format, num_msaa_samples)?;
let buffer_or_image = BufferOrImage::new(buffer_backend_handle, ResourceType::Image);
let inner_key = buffer_store
.loaded_buffers_and_images
.insert(buffer_or_image);
Ok((
BufferImageHandle {
inner_key,
resource_type: ResourceType::Image,
buffer_store: Arc::downgrade(this),
},
buffer_or_image,
))
}
fn destroy_image(&mut self, inner_key: DefaultKey) -> SarektResult<()> {
let image = self.loaded_buffers_and_images.remove(inner_key);
if image.is_none() {
return Err(SarektError::UnknownResource);
}
self
.buffer_image_loader
.delete_buffer_or_image(image.unwrap().handle)
}
pub(crate) fn get_buffer(
&self, handle: &BufferImageHandle<BL>,
) -> SarektResult<&BufferOrImage<BL::BackendHandle>> {
if !matches!(handle.resource_type, ResourceType::Buffer(_)) {
return Err(SarektError::IncorrectResourceType);
}
let buffer = self.loaded_buffers_and_images.get(handle.inner_key);
if let Some(buffer) = buffer {
return Ok(buffer);
}
Err(SarektError::UnknownResource)
}
pub(crate) fn get_image(
&self, handle: &BufferImageHandle<BL>,
) -> SarektResult<&BufferOrImage<BL::BackendHandle>> {
if !matches!(handle.resource_type, ResourceType::Image) {
return Err(SarektError::IncorrectResourceType);
}
let image = self.loaded_buffers_and_images.get(handle.inner_key);
if let Some(image) = image {
return Ok(image);
}
Err(SarektError::UnknownResource)
}
pub(crate) fn destroy_all_images_and_buffers(&mut self) {
for resource in self.loaded_buffers_and_images.iter() {
if let Err(err) = self
.buffer_image_loader
.delete_buffer_or_image(resource.1.handle)
{
warn!(
"Buffer/image not destroyed, maybe it was already? Error: {:?}",
err
);
}
}
self.loaded_buffers_and_images.clear();
}
}
#[derive(Copy, Clone, Debug)]
pub struct BufferOrImage<BackendHandle: BackendHandleTrait + Copy> {
pub handle: BackendHandle,
pub resource_type: ResourceType,
}
impl<BackendHandle: BackendHandleTrait + Copy> BufferOrImage<BackendHandle> {
fn new(buffer_handle: BackendHandle, buffer_type: ResourceType) -> Self {
Self {
handle: buffer_handle,
resource_type: buffer_type,
}
}
}
pub enum MagnificationMinificationFilter {
Linear,
Nearest,
}
pub enum TextureAddressMode {
Repeat,
MirroredRepeat,
ClampToEdge,
MirroredClampToEdge,
}