use std::sync::Arc;
use glam::{UVec2, UVec3};
use offset_allocator::{Allocation, Allocator};
use tokio::sync::Mutex;
use vulkano::{
buffer::BufferContents,
descriptor_set::{DescriptorSet, WriteDescriptorSet, layout::DescriptorSetLayout},
image::{
Image, ImageType,
sampler::{
Sampler,
ycbcr::{ChromaLocation, SamplerYcbcrModelConversion, SamplerYcbcrRange},
},
view::ImageView,
},
pipeline::{PipelineBindPoint, PipelineLayout},
shader::ShaderStages,
};
use crate::{
Context,
command_buffer::StarlightCommandBuffer,
materials::image_common::get_descriptor_set_layout_info,
resource_manager::{ResourceHandle, ResourceManager},
resources::buffer::Bda,
};
pub mod dma_image;
pub mod local_image;
pub mod openxr_attachment;
pub mod transient_attachment;
pub mod wsi_swapchain;
#[derive(Debug, BufferContents, Clone, Copy)]
#[repr(C)]
pub struct ImageRefData {
image_index: u32,
sampler_index: u32,
flags: u8,
}
impl ImageRefData {
pub const SOFTWARE_SRGB: u8 = 1 << 0;
pub const ALPHA_UNMULTIPLICATION: u8 = 1 << 1;
pub const ALPHA_MULTIPLICATION: u8 = 1 << 2;
}
pub struct ImageRefInfo {
requires_software_srgb: bool,
requires_unmultiplication: bool,
requires_multiplication: bool,
}
pub trait ImageRefSource {
fn get_image_ref_info(&self) -> ImageRefInfo;
fn get_image(&self) -> Arc<Image>;
fn get_image_view(&self) -> Arc<ImageView>;
}
#[derive(Clone, Copy, Debug)]
pub struct YcbcrMetadata {
coefficients: SamplerYcbcrModelConversion,
range: SamplerYcbcrRange,
chroma_location_x: ChromaLocation,
chroma_location_y: ChromaLocation,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AlphaMode {
PremultipliedElectrical,
PremultipliedOptical,
Unpremmultiplied,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ImageResolution {
D1(u32),
D2(UVec2),
D3(UVec3),
}
impl ImageResolution {
pub fn extents(&self) -> [u32; 3] {
match *self {
ImageResolution::D1(x) => [x, 1, 1],
ImageResolution::D2(UVec2 { x, y }) => [x, y, 1],
ImageResolution::D3(UVec3 { x, y, z }) => [x, y, z],
}
}
pub fn image_type(&self) -> ImageType {
match *self {
ImageResolution::D1(_) => ImageType::Dim1d,
ImageResolution::D2(_) => ImageType::Dim2d,
ImageResolution::D3(_) => ImageType::Dim3d,
}
}
}
pub struct SamplerRef {
sampler: Arc<Sampler>,
alloc: Allocation,
allocator: Arc<Mutex<Allocator>>,
}
impl std::fmt::Debug for SamplerRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SamplerRef")
.field("sampler", &self.sampler)
.field("alloc", &self.alloc.offset)
.field("allocator", &self.allocator)
.finish()
}
}
impl Drop for SamplerRef {
fn drop(&mut self) {
let alloc = self.alloc.clone();
let sampler = self.sampler.clone();
let allocator = self.allocator.clone();
tokio::spawn(async move {
allocator.lock().await.free(alloc);
let _sampler = sampler;
});
}
}
pub struct ImageManager {
descriptor_set: DescriptorSet,
refs: Arc<ResourceManager<ImageRefData>>,
sampler_alloc: Arc<Mutex<Allocator>>,
}
impl ImageManager {
pub fn new(ctx: &Context, stages: ShaderStages) -> ImageManager {
let layout = DescriptorSetLayout::new(
ctx.device.clone(),
get_descriptor_set_layout_info(ctx, stages),
)
.unwrap();
let count = layout.variable_descriptor_count();
let descriptor_set =
DescriptorSet::new_variable(ctx.descriptor_set_alloc.clone(), layout, count, [], [])
.unwrap();
let descriptor_set = Arc::try_unwrap(descriptor_set).unwrap();
Self {
refs: ResourceManager::new(64),
descriptor_set,
sampler_alloc: Arc::new(Mutex::new(Allocator::new(256))),
}
}
pub async fn alloc_sampler(&mut self, sampler: Arc<Sampler>) -> Option<Arc<SamplerRef>> {
let alloc = self.sampler_alloc.lock().await.allocate(1)?;
self.descriptor_set
.update(
[WriteDescriptorSet::sampler_array(
0,
alloc.offset,
[sampler.clone()],
)],
[],
)
.unwrap();
Some(
SamplerRef {
sampler,
alloc,
allocator: self.sampler_alloc.clone(),
}
.into(),
)
}
pub async fn alloc(
&mut self,
ctx: &Context,
image: &impl ImageRefSource,
sampler: Arc<SamplerRef>,
) -> Arc<ImageRef> {
let info = image.get_image_ref_info();
let image_view = image.get_image_view();
let mut flags = 0;
if info.requires_software_srgb {
flags |= ImageRefData::SOFTWARE_SRGB;
}
if info.requires_unmultiplication {
flags |= ImageRefData::ALPHA_UNMULTIPLICATION;
}
if info.requires_multiplication {
flags |= ImageRefData::ALPHA_MULTIPLICATION;
}
let alloc = self
.refs
.alloc(
ctx,
ImageRefData {
image_index: 0,
sampler_index: 0,
flags,
},
)
.await
.unwrap();
alloc
.new_wite_op()
.write(|mut v| v.image_index = alloc.alloc_index())
.await
.unwrap();
self.descriptor_set
.update(
[WriteDescriptorSet::image_view_array(
1,
alloc.alloc_index(),
[image_view],
)],
[],
)
.unwrap();
ImageRef {
ref_data: alloc,
sampler,
}
.into()
}
pub fn bind(
&self,
cmds: &mut StarlightCommandBuffer,
bind_point: PipelineBindPoint,
layout: &PipelineLayout,
) -> Result<(), Box<vulkano::ValidationError>> {
unsafe {
cmds.inner().bind_descriptor_sets(
bind_point,
layout,
0,
&[self.descriptor_set.as_raw()],
&[],
)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct ImageRef {
sampler: Arc<SamplerRef>,
ref_data: ResourceHandle<ImageRefData>,
}
impl ImageRef {
pub fn bda<'a>(&'a self) -> Bda<'a, ImageRefData> {
self.ref_data.device_address().unwrap()
}
}