use crate::passes::ImageComp;
use spirv::{Dim, ImageFormat};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TextureDimension {
D1,
D2,
D3,
Cube,
Buffer,
}
impl TextureDimension {
pub fn to_spirv_dim(self) -> Dim {
match self {
TextureDimension::D1 => Dim::Dim1D,
TextureDimension::D2 => Dim::Dim2D,
TextureDimension::D3 => Dim::Dim3D,
TextureDimension::Cube => Dim::DimCube,
TextureDimension::Buffer => Dim::DimBuffer,
}
}
pub fn from_spirv_dim(dim: Dim) -> Self {
match dim {
Dim::Dim1D => TextureDimension::D1,
Dim::Dim3D => TextureDimension::D3,
Dim::DimCube => TextureDimension::Cube,
Dim::DimBuffer => TextureDimension::Buffer,
_ => TextureDimension::D2,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TextureComponent {
Float,
Sint,
Uint,
}
impl TextureComponent {
pub fn to_image_comp(self) -> ImageComp {
match self {
TextureComponent::Float => ImageComp::Float,
TextureComponent::Sint => ImageComp::Sint,
TextureComponent::Uint => ImageComp::Uint,
}
}
pub fn from_image_comp(comp: ImageComp) -> Self {
match comp {
ImageComp::Float => TextureComponent::Float,
ImageComp::Sint => TextureComponent::Sint,
ImageComp::Uint => TextureComponent::Uint,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TextureFormat {
Rgba32f,
Rgba16f,
Rgba8ui,
Rgba16ui,
Rgba8i,
}
impl TextureFormat {
pub fn to_spirv_format(self) -> ImageFormat {
match self {
TextureFormat::Rgba32f => ImageFormat::Rgba32f,
TextureFormat::Rgba16f => ImageFormat::Rgba16f,
TextureFormat::Rgba8ui => ImageFormat::Rgba8ui,
TextureFormat::Rgba16ui => ImageFormat::Rgba16ui,
TextureFormat::Rgba8i => ImageFormat::Rgba8i,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TextureShape {
pub dimension: TextureDimension,
pub arrayed: bool,
pub multisampled: bool,
pub component: TextureComponent,
pub writable: bool,
pub array_ref: bool,
pub storage_format: Option<TextureFormat>,
}
pub fn texture_shape_from_name(name: &str) -> TextureShape {
let head = name.split_once('<').map(|(h, _)| h).unwrap_or(name);
let (dimension, arrayed) = if head.contains("texture_buffer") {
(TextureDimension::Buffer, false)
} else if head.contains("1d_array") {
(TextureDimension::D1, true)
} else if head.contains("1d") {
(TextureDimension::D1, false)
} else if head.contains("3d") {
(TextureDimension::D3, false)
} else if head.contains("cube_array") {
(TextureDimension::Cube, true)
} else if head.contains("cube") {
(TextureDimension::Cube, false)
} else if head.contains("2d_array") {
(TextureDimension::D2, true)
} else {
(TextureDimension::D2, false)
};
let multisampled = head.contains("_ms");
let component = texture_component_from_name(name);
let (writable, array_ref) = texture_access_from_name(name);
let storage_format = if writable {
Some(storage_format_from_name(name, component))
} else {
None
};
TextureShape {
dimension,
arrayed,
multisampled,
component,
writable,
array_ref,
storage_format,
}
}
fn storage_format_from_name(name: &str, component: TextureComponent) -> TextureFormat {
match component {
TextureComponent::Float => {
if name.contains("<half") {
TextureFormat::Rgba16f
} else {
TextureFormat::Rgba32f
}
}
TextureComponent::Uint => {
if name.contains("<ushort") {
TextureFormat::Rgba16ui
} else {
TextureFormat::Rgba8ui
}
}
TextureComponent::Sint => TextureFormat::Rgba8i,
}
}
fn texture_component_from_name(name: &str) -> TextureComponent {
let Some((_, rest)) = name.split_once('<') else {
return TextureComponent::Float;
};
let scalar = rest
.split(|c: char| c == ',' || c == '>' || c.is_whitespace())
.find(|part| !part.is_empty())
.unwrap_or("");
let scalar = scalar.rsplit('<').next().unwrap_or(scalar);
match scalar {
"uint" | "ushort" | "uchar" => TextureComponent::Uint,
"int" | "short" | "char" => TextureComponent::Sint,
_ => TextureComponent::Float,
}
}
fn texture_access_from_name(name: &str) -> (bool, bool) {
let array_ref = name.contains("array_ref<") || name.contains("array_ref <");
let Some((_, rest)) = name.split_once('<') else {
return (false, array_ref);
};
let Some(inner) = rest.split('>').next() else {
return (false, array_ref);
};
let mut fields = inner.split(',').map(str::trim);
let _scalar = fields.next();
let writable = matches!(fields.next(), Some("write") | Some("read_write"));
(writable, array_ref)
}