use format::Format;
use image::Dimensions;
use std::cmp;
use std::error;
use std::fmt;
use std::ops::BitOr;
use sync::AccessFlagBits;
use sync::PipelineStages;
use vk;
#[derive(Debug, Clone)]
pub struct DescriptorDesc {
pub ty: DescriptorDescTy,
pub array_count: u32,
pub stages: ShaderStages,
pub readonly: bool,
}
impl DescriptorDesc {
#[inline]
pub fn is_superset_of(&self, other: &DescriptorDesc)
-> Result<(), DescriptorDescSupersetError> {
self.ty.is_superset_of(&other.ty)?;
self.stages.is_superset_of(&other.stages)?;
if self.array_count < other.array_count {
return Err(DescriptorDescSupersetError::ArrayTooSmall {
len: self.array_count,
required: other.array_count,
});
}
if self.readonly && !other.readonly {
return Err(DescriptorDescSupersetError::MutabilityRequired);
}
Ok(())
}
#[inline]
pub fn union(&self, other: &DescriptorDesc) -> Option<DescriptorDesc> {
if self.ty != other.ty {
return None;
}
Some(DescriptorDesc {
ty: self.ty.clone(),
array_count: cmp::max(self.array_count, other.array_count),
stages: self.stages | other.stages,
readonly: self.readonly && other.readonly,
})
}
pub fn pipeline_stages_and_access(&self) -> (PipelineStages, AccessFlagBits) {
let stages: PipelineStages = self.stages.into();
let access = match self.ty {
DescriptorDescTy::Sampler => panic!(),
DescriptorDescTy::CombinedImageSampler(_) |
DescriptorDescTy::Image(_) => {
AccessFlagBits {
shader_read: true,
shader_write: !self.readonly,
..AccessFlagBits::none()
}
},
DescriptorDescTy::TexelBuffer { .. } => {
AccessFlagBits {
shader_read: true,
shader_write: !self.readonly,
..AccessFlagBits::none()
}
},
DescriptorDescTy::InputAttachment { .. } => {
AccessFlagBits {
input_attachment_read: true,
..AccessFlagBits::none()
}
},
DescriptorDescTy::Buffer(ref buf) => {
if buf.storage {
AccessFlagBits {
shader_read: true,
shader_write: !self.readonly,
..AccessFlagBits::none()
}
} else {
AccessFlagBits {
uniform_read: true,
..AccessFlagBits::none()
}
}
},
};
(stages, access)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DescriptorDescTy {
Sampler,
CombinedImageSampler(DescriptorImageDesc),
Image(DescriptorImageDesc),
TexelBuffer {
storage: bool,
format: Option<Format>,
},
InputAttachment {
multisampled: bool,
array_layers: DescriptorImageDescArray,
},
Buffer(DescriptorBufferDesc),
}
impl DescriptorDescTy {
pub fn ty(&self) -> Option<DescriptorType> {
Some(match *self {
DescriptorDescTy::Sampler => DescriptorType::Sampler,
DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
DescriptorDescTy::Image(ref desc) => {
if desc.sampled {
DescriptorType::SampledImage
} else {
DescriptorType::StorageImage
}
},
DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
DescriptorDescTy::Buffer(ref desc) => {
let dynamic = match desc.dynamic {
Some(d) => d,
None => return None,
};
match (desc.storage, dynamic) {
(false, false) => DescriptorType::UniformBuffer,
(true, false) => DescriptorType::StorageBuffer,
(false, true) => DescriptorType::UniformBufferDynamic,
(true, true) => DescriptorType::StorageBufferDynamic,
}
},
DescriptorDescTy::TexelBuffer { storage, .. } => {
if storage {
DescriptorType::StorageTexelBuffer
} else {
DescriptorType::UniformTexelBuffer
}
},
})
}
#[inline]
pub fn is_superset_of(&self, other: &DescriptorDescTy)
-> Result<(), DescriptorDescSupersetError> {
match (self, other) {
(&DescriptorDescTy::Sampler, &DescriptorDescTy::Sampler) => Ok(()),
(&DescriptorDescTy::CombinedImageSampler(ref me),
&DescriptorDescTy::CombinedImageSampler(ref other)) => me.is_superset_of(other),
(&DescriptorDescTy::Image(ref me), &DescriptorDescTy::Image(ref other)) =>
me.is_superset_of(other),
(&DescriptorDescTy::InputAttachment {
multisampled: me_multisampled,
array_layers: me_array_layers,
},
&DescriptorDescTy::InputAttachment {
multisampled: other_multisampled,
array_layers: other_array_layers,
}) => {
if me_multisampled != other_multisampled {
return Err(DescriptorDescSupersetError::MultisampledMismatch {
provided: me_multisampled,
expected: other_multisampled,
});
}
if me_array_layers != other_array_layers {
return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
provided: me_array_layers,
required: other_array_layers,
});
}
Ok(())
},
(&DescriptorDescTy::Buffer(ref me), &DescriptorDescTy::Buffer(ref other)) => {
if me.storage != other.storage {
return Err(DescriptorDescSupersetError::TypeMismatch);
}
match (me.dynamic, other.dynamic) {
(Some(_), None) => Ok(()),
(Some(m), Some(o)) => if m == o {
Ok(())
} else {
Err(DescriptorDescSupersetError::TypeMismatch)
},
(None, None) => Ok(()),
(None, Some(_)) => Err(DescriptorDescSupersetError::TypeMismatch),
}
},
(&DescriptorDescTy::TexelBuffer {
storage: me_storage,
format: me_format,
},
&DescriptorDescTy::TexelBuffer {
storage: other_storage,
format: other_format,
}) => {
if me_storage != other_storage {
return Err(DescriptorDescSupersetError::TypeMismatch);
}
match (me_format, other_format) {
(Some(_), None) => Ok(()),
(Some(m), Some(o)) => if m == o {
Ok(())
} else {
Err(DescriptorDescSupersetError::FormatMismatch {
provided: Some(m),
expected: o,
})
},
(None, None) => Ok(()),
(None, Some(a)) => Err(DescriptorDescSupersetError::FormatMismatch {
provided: Some(a),
expected: a,
}),
}
},
_ => Err(DescriptorDescSupersetError::TypeMismatch),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DescriptorImageDesc {
pub sampled: bool,
pub dimensions: DescriptorImageDescDimensions,
pub format: Option<Format>,
pub multisampled: bool,
pub array_layers: DescriptorImageDescArray,
}
impl DescriptorImageDesc {
#[inline]
pub fn is_superset_of(&self, other: &DescriptorImageDesc)
-> Result<(), DescriptorDescSupersetError> {
if self.dimensions != other.dimensions {
return Err(DescriptorDescSupersetError::DimensionsMismatch {
provided: self.dimensions,
expected: other.dimensions,
});
}
if self.multisampled != other.multisampled {
return Err(DescriptorDescSupersetError::MultisampledMismatch {
provided: self.multisampled,
expected: other.multisampled,
});
}
match (self.format, other.format) {
(Some(a), Some(b)) => if a != b {
return Err(DescriptorDescSupersetError::FormatMismatch {
provided: Some(a),
expected: b,
});
},
(Some(_), None) => (),
(None, None) => (),
(None, Some(a)) => {
return Err(DescriptorDescSupersetError::FormatMismatch {
provided: None,
expected: a,
});
},
};
match (self.array_layers, other.array_layers) {
(DescriptorImageDescArray::NonArrayed, DescriptorImageDescArray::NonArrayed) => (),
(DescriptorImageDescArray::Arrayed { max_layers: my_max },
DescriptorImageDescArray::Arrayed { max_layers: other_max }) => {
match (my_max, other_max) {
(Some(m), Some(o)) => if m < o {
return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
provided: DescriptorImageDescArray::Arrayed {
max_layers: my_max,
},
required: DescriptorImageDescArray::Arrayed {
max_layers: other_max,
},
});
},
(Some(_), None) => (),
(None, Some(m)) => {
return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
provided: DescriptorImageDescArray::Arrayed {
max_layers: my_max,
},
required: DescriptorImageDescArray::Arrayed {
max_layers: other_max,
},
});
},
(None, None) => (),
};
},
(a, b) => return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
provided: a,
required: b,
}),
};
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescArray {
NonArrayed,
Arrayed { max_layers: Option<u32> },
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescDimensions {
OneDimensional,
TwoDimensional,
ThreeDimensional,
Cube,
}
impl DescriptorImageDescDimensions {
#[inline]
pub fn from_dimensions(dims: Dimensions) -> DescriptorImageDescDimensions {
match dims {
Dimensions::Dim1d { .. } => DescriptorImageDescDimensions::OneDimensional,
Dimensions::Dim1dArray { .. } => DescriptorImageDescDimensions::OneDimensional,
Dimensions::Dim2d { .. } => DescriptorImageDescDimensions::TwoDimensional,
Dimensions::Dim2dArray { .. } => DescriptorImageDescDimensions::TwoDimensional,
Dimensions::Dim3d { .. } => DescriptorImageDescDimensions::ThreeDimensional,
Dimensions::Cubemap { .. } => DescriptorImageDescDimensions::Cube,
Dimensions::CubemapArray { .. } => DescriptorImageDescDimensions::Cube,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DescriptorBufferDesc {
pub dynamic: Option<bool>,
pub storage: bool,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum DescriptorType {
Sampler = vk::DESCRIPTOR_TYPE_SAMPLER,
CombinedImageSampler = vk::DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
SampledImage = vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE,
StorageImage = vk::DESCRIPTOR_TYPE_STORAGE_IMAGE,
UniformTexelBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
StorageTexelBuffer = vk::DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
UniformBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,
StorageBuffer = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER,
UniformBufferDynamic = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
StorageBufferDynamic = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
InputAttachment = vk::DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DescriptorDescSupersetError {
ArrayTooSmall { len: u32, required: u32 },
TypeMismatch,
MutabilityRequired,
ShaderStagesNotSuperset,
DimensionsMismatch {
provided: DescriptorImageDescDimensions,
expected: DescriptorImageDescDimensions,
},
FormatMismatch {
provided: Option<Format>,
expected: Format,
},
MultisampledMismatch { provided: bool, expected: bool },
IncompatibleArrayLayers {
provided: DescriptorImageDescArray,
required: DescriptorImageDescArray,
},
}
impl error::Error for DescriptorDescSupersetError {
#[inline]
fn description(&self) -> &str {
match *self {
DescriptorDescSupersetError::ArrayTooSmall { .. } => {
"the number of array elements of the descriptor is smaller than expected"
},
DescriptorDescSupersetError::TypeMismatch => {
"the descriptor type doesn't match the type of the other descriptor"
},
DescriptorDescSupersetError::MutabilityRequired => {
"the descriptor is marked as read-only, but the other is not"
},
DescriptorDescSupersetError::ShaderStagesNotSuperset => {
"the shader stages are not a superset of one another"
},
DescriptorDescSupersetError::DimensionsMismatch { .. } => {
"mismatch between the dimensions of the two descriptors"
},
DescriptorDescSupersetError::FormatMismatch { .. } => {
"mismatch between the format of the two descriptors"
},
DescriptorDescSupersetError::MultisampledMismatch { .. } => {
"mismatch between whether the descriptors are multisampled"
},
DescriptorDescSupersetError::IncompatibleArrayLayers { .. } => {
"the array layers of the descriptors aren't compatible"
},
}
}
}
impl fmt::Display for DescriptorDescSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<ShaderStagesSupersetError> for DescriptorDescSupersetError {
#[inline]
fn from(err: ShaderStagesSupersetError) -> DescriptorDescSupersetError {
match err {
ShaderStagesSupersetError::NotSuperset => {
DescriptorDescSupersetError::ShaderStagesNotSuperset
},
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderStages {
pub vertex: bool,
pub tessellation_control: bool,
pub tessellation_evaluation: bool,
pub geometry: bool,
pub fragment: bool,
pub compute: bool,
}
impl ShaderStages {
#[inline]
pub fn all() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: true,
}
}
#[inline]
pub fn none() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: false,
}
}
#[inline]
pub fn all_graphics() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: false,
}
}
#[inline]
pub fn compute() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: true,
}
}
#[inline]
pub fn is_superset_of(&self, other: &ShaderStages) -> Result<(), ShaderStagesSupersetError> {
if (self.vertex || !other.vertex) &&
(self.tessellation_control || !other.tessellation_control) &&
(self.tessellation_evaluation || !other.tessellation_evaluation) &&
(self.geometry || !other.geometry) &&
(self.fragment || !other.fragment) && (self.compute || !other.compute)
{
Ok(())
} else {
Err(ShaderStagesSupersetError::NotSuperset)
}
}
#[inline]
pub fn intersects(&self, other: &ShaderStages) -> bool {
(self.vertex && other.vertex) ||
(self.tessellation_control && other.tessellation_control) ||
(self.tessellation_evaluation && other.tessellation_evaluation) ||
(self.geometry && other.geometry) || (self.fragment && other.fragment) ||
(self.compute && other.compute)
}
#[inline]
pub(crate) fn into_vulkan_bits(self) -> vk::ShaderStageFlags {
let mut result = 0;
if self.vertex {
result |= vk::SHADER_STAGE_VERTEX_BIT;
}
if self.tessellation_control {
result |= vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT;
}
if self.tessellation_evaluation {
result |= vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
}
if self.geometry {
result |= vk::SHADER_STAGE_GEOMETRY_BIT;
}
if self.fragment {
result |= vk::SHADER_STAGE_FRAGMENT_BIT;
}
if self.compute {
result |= vk::SHADER_STAGE_COMPUTE_BIT;
}
result
}
}
impl BitOr for ShaderStages {
type Output = ShaderStages;
#[inline]
fn bitor(self, other: ShaderStages) -> ShaderStages {
ShaderStages {
vertex: self.vertex || other.vertex,
tessellation_control: self.tessellation_control || other.tessellation_control,
tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
geometry: self.geometry || other.geometry,
fragment: self.fragment || other.fragment,
compute: self.compute || other.compute,
}
}
}
impl From<ShaderStages> for PipelineStages {
#[inline]
fn from(stages: ShaderStages) -> PipelineStages {
PipelineStages {
vertex_shader: stages.vertex,
tessellation_control_shader: stages.tessellation_control,
tessellation_evaluation_shader: stages.tessellation_evaluation,
geometry_shader: stages.geometry,
fragment_shader: stages.fragment,
compute_shader: stages.compute,
..PipelineStages::none()
}
}
}
#[derive(Debug, Clone)]
pub enum ShaderStagesSupersetError {
NotSuperset,
}
impl error::Error for ShaderStagesSupersetError {
#[inline]
fn description(&self) -> &str {
match *self {
ShaderStagesSupersetError::NotSuperset => {
"shader stages not a superset"
},
}
}
}
impl fmt::Display for ShaderStagesSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}