use std::cmp;
use std::error;
use std::fmt;
use std::sync::Arc;
use SafeDeref;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor::ShaderStages;
use descriptor::descriptor_set::DescriptorSetsCollection;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::pipeline_layout::limits_check;
use descriptor::pipeline_layout::PipelineLayout;
use descriptor::pipeline_layout::PipelineLayoutCreationError;
use descriptor::pipeline_layout::PipelineLayoutDescUnion;
use descriptor::pipeline_layout::PipelineLayoutSys;
use device::Device;
use device::DeviceOwned;
pub unsafe trait PipelineLayoutAbstract: PipelineLayoutDesc + DeviceOwned {
fn sys(&self) -> PipelineLayoutSys;
fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<UnsafeDescriptorSetLayout>>;
}
unsafe impl<T> PipelineLayoutAbstract for T
where T: SafeDeref,
T::Target: PipelineLayoutAbstract
{
#[inline]
fn sys(&self) -> PipelineLayoutSys {
(**self).sys()
}
#[inline]
fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<UnsafeDescriptorSetLayout>> {
(**self).descriptor_set_layout(index)
}
}
pub unsafe trait PipelineLayoutDesc {
fn num_sets(&self) -> usize;
fn num_bindings_in_set(&self, set: usize) -> Option<usize>;
fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc>;
#[inline]
fn provided_set_layout(&self, _set: usize) -> Option<Arc<UnsafeDescriptorSetLayout>> {
None
}
fn num_push_constants_ranges(&self) -> usize;
fn push_constants_range(&self, num: usize) -> Option<PipelineLayoutDescPcRange>;
#[inline]
fn union<T>(self, other: T) -> PipelineLayoutDescUnion<Self, T>
where Self: Sized
{
PipelineLayoutDescUnion::new(self, other)
}
#[inline]
fn check_against_limits(&self, device: &Device)
-> Result<(), limits_check::PipelineLayoutLimitsError>
{
limits_check::check_desc_against_limits(self, device.physical_device().limits())
}
#[inline]
fn build(self, device: Arc<Device>) -> Result<PipelineLayout<Self>, PipelineLayoutCreationError>
where Self: Sized
{
PipelineLayout::new(device, self)
}
}
#[derive(Debug, Copy, Clone)]
pub struct PipelineLayoutDescPcRange {
pub offset: usize,
pub size: usize,
pub stages: ShaderStages,
}
unsafe impl<T> PipelineLayoutDesc for T
where T: SafeDeref,
T::Target: PipelineLayoutDesc
{
#[inline]
fn num_sets(&self) -> usize {
(**self).num_sets()
}
#[inline]
fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
(**self).num_bindings_in_set(set)
}
#[inline]
fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
(**self).descriptor(set, binding)
}
#[inline]
fn num_push_constants_ranges(&self) -> usize {
(**self).num_push_constants_ranges()
}
#[inline]
fn push_constants_range(&self, num: usize) -> Option<PipelineLayoutDescPcRange> {
(**self).push_constants_range(num)
}
}
pub unsafe trait PipelineLayoutSuperset<Other: ?Sized>: PipelineLayoutDesc
where Other: PipelineLayoutDesc
{
fn ensure_superset_of(&self, &Other) -> Result<(), PipelineLayoutNotSupersetError>;
}
unsafe impl<T: ?Sized, U: ?Sized> PipelineLayoutSuperset<U> for T
where T: PipelineLayoutDesc,
U: PipelineLayoutDesc
{
fn ensure_superset_of(&self, other: &U) -> Result<(), PipelineLayoutNotSupersetError> {
for set_num in 0 .. cmp::max(self.num_sets(), other.num_sets()) {
let other_num_bindings = other.num_bindings_in_set(set_num).unwrap_or(0);
let self_num_bindings = self.num_bindings_in_set(set_num).unwrap_or(0);
if self_num_bindings < other_num_bindings {
return Err(PipelineLayoutNotSupersetError::DescriptorsCountMismatch {
set_num: set_num as u32,
self_num_descriptors: self_num_bindings as u32,
other_num_descriptors: other_num_bindings as u32,
});
}
for desc_num in 0 .. other_num_bindings {
match (self.descriptor(set_num, desc_num), other.descriptor(set_num, desc_num)) {
(Some(mine), Some(other)) => {
if !mine.is_superset_of(&other) {
return Err(PipelineLayoutNotSupersetError::IncompatibleDescriptors {
set_num: set_num as u32,
descriptor: desc_num as u32,
});
}
},
(None, Some(_)) =>
return Err(PipelineLayoutNotSupersetError::ExpectedEmptyDescriptor {
set_num: set_num as u32,
descriptor: desc_num as u32,
}),
_ => (),
}
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PipelineLayoutNotSupersetError {
DescriptorsCountMismatch {
set_num: u32,
self_num_descriptors: u32,
other_num_descriptors: u32,
},
ExpectedEmptyDescriptor { set_num: u32, descriptor: u32 },
IncompatibleDescriptors {
set_num: u32,
descriptor: u32,
},
}
impl error::Error for PipelineLayoutNotSupersetError {
#[inline]
fn description(&self) -> &str {
match *self {
PipelineLayoutNotSupersetError::DescriptorsCountMismatch { .. } => {
"there are more descriptors in the child than in the parent layout"
},
PipelineLayoutNotSupersetError::ExpectedEmptyDescriptor { .. } => {
"expected an empty descriptor, but got something instead"
},
PipelineLayoutNotSupersetError::IncompatibleDescriptors { .. } => {
"two descriptors are incompatible"
},
}
}
}
impl fmt::Display for PipelineLayoutNotSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
pub unsafe trait PipelineLayoutSetsCompatible<Other: ?Sized>: PipelineLayoutDesc
where Other: DescriptorSetsCollection
{
fn is_compatible(&self, &Other) -> bool;
}
unsafe impl<T: ?Sized, U: ?Sized> PipelineLayoutSetsCompatible<U> for T
where T: PipelineLayoutDesc,
U: DescriptorSetsCollection
{
fn is_compatible(&self, sets: &U) -> bool {
true
}
}
pub unsafe trait PipelineLayoutPushConstantsCompatible<Pc: ?Sized>
: PipelineLayoutDesc {
fn is_compatible(&self, &Pc) -> bool;
}
unsafe impl<T: ?Sized, U: ?Sized> PipelineLayoutPushConstantsCompatible<U> for T
where T: PipelineLayoutDesc
{
fn is_compatible(&self, _: &U) -> bool {
true
}
}