use std::error;
use std::fmt;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::ShaderStages;
use descriptor::pipeline_layout::PipelineLayoutDesc;
use descriptor::pipeline_layout::PipelineLayoutDescPcRange;
use instance::Limits;
pub fn check_desc_against_limits<D>(desc: &D, limits: Limits)
-> Result<(), PipelineLayoutLimitsError>
where D: ?Sized + PipelineLayoutDesc
{
let mut num_resources = Counter::default();
let mut num_samplers = Counter::default();
let mut num_uniform_buffers = Counter::default();
let mut num_uniform_buffers_dynamic = 0;
let mut num_storage_buffers = Counter::default();
let mut num_storage_buffers_dynamic = 0;
let mut num_sampled_images = Counter::default();
let mut num_storage_images = Counter::default();
let mut num_input_attachments = Counter::default();
for set in 0 .. desc.num_sets() {
let num_bindings_in_set = match desc.num_bindings_in_set(set) {
None => continue,
Some(n) => n,
};
for binding in 0 .. num_bindings_in_set {
let descriptor = match desc.descriptor(set, binding) {
None => continue,
Some(n) => n,
};
num_resources.increment(descriptor.array_count, &descriptor.stages);
match descriptor.ty.ty().expect("Not implemented yet") {
DescriptorType::Sampler => {
num_samplers.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::CombinedImageSampler => {
num_samplers.increment(descriptor.array_count, &descriptor.stages);
num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::SampledImage |
DescriptorType::UniformTexelBuffer => {
num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::StorageImage |
DescriptorType::StorageTexelBuffer => {
num_storage_images.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::UniformBuffer => {
num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::UniformBufferDynamic => {
num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
num_uniform_buffers_dynamic += 1;
},
DescriptorType::StorageBuffer => {
num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
},
DescriptorType::StorageBufferDynamic => {
num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
num_storage_buffers_dynamic += 1;
},
DescriptorType::InputAttachment => {
num_input_attachments.increment(descriptor.array_count, &descriptor.stages);
},
}
}
}
if desc.num_sets() > limits.max_bound_descriptor_sets() as usize {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
limit: limits.max_bound_descriptor_sets() as usize,
requested: desc.num_sets(),
});
}
if num_resources.max_per_stage() > limits.max_per_stage_resources() {
return Err(PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
limit: limits.max_per_stage_resources(),
requested: num_resources.max_per_stage(),
});
}
if num_samplers.max_per_stage() > limits.max_per_stage_descriptor_samplers() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
limit: limits.max_per_stage_descriptor_samplers(),
requested: num_samplers.max_per_stage(),
});
}
if num_uniform_buffers.max_per_stage() > limits.max_per_stage_descriptor_uniform_buffers() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
limit: limits.max_per_stage_descriptor_uniform_buffers(),
requested: num_uniform_buffers.max_per_stage(),
});
}
if num_storage_buffers.max_per_stage() > limits.max_per_stage_descriptor_storage_buffers() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
limit: limits.max_per_stage_descriptor_storage_buffers(),
requested: num_storage_buffers.max_per_stage(),
});
}
if num_sampled_images.max_per_stage() > limits.max_per_stage_descriptor_sampled_images() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
limit: limits.max_per_stage_descriptor_sampled_images(),
requested: num_sampled_images.max_per_stage(),
});
}
if num_storage_images.max_per_stage() > limits.max_per_stage_descriptor_storage_images() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
limit: limits.max_per_stage_descriptor_storage_images(),
requested: num_storage_images.max_per_stage(),
});
}
if num_input_attachments.max_per_stage() > limits.max_per_stage_descriptor_input_attachments() {
return Err(PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
limit: limits.max_per_stage_descriptor_input_attachments(),
requested: num_input_attachments.max_per_stage(),
});
}
if num_samplers.total > limits.max_descriptor_set_samplers() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
limit: limits.max_descriptor_set_samplers(),
requested: num_samplers.total,
});
}
if num_uniform_buffers.total > limits.max_descriptor_set_uniform_buffers() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
limit: limits.max_descriptor_set_uniform_buffers(),
requested: num_uniform_buffers.total,
});
}
if num_uniform_buffers_dynamic > limits.max_descriptor_set_uniform_buffers_dynamic() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
limit: limits.max_descriptor_set_uniform_buffers_dynamic(),
requested: num_uniform_buffers_dynamic,
});
}
if num_storage_buffers.total > limits.max_descriptor_set_storage_buffers() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
limit: limits.max_descriptor_set_storage_buffers(),
requested: num_storage_buffers.total,
});
}
if num_storage_buffers_dynamic > limits.max_descriptor_set_storage_buffers_dynamic() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
limit: limits.max_descriptor_set_storage_buffers_dynamic(),
requested: num_storage_buffers_dynamic,
});
}
if num_sampled_images.total > limits.max_descriptor_set_sampled_images() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
limit: limits.max_descriptor_set_sampled_images(),
requested: num_sampled_images.total,
});
}
if num_storage_images.total > limits.max_descriptor_set_storage_images() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
limit: limits.max_descriptor_set_storage_images(),
requested: num_storage_images.total,
});
}
if num_input_attachments.total > limits.max_descriptor_set_input_attachments() {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
limit: limits.max_descriptor_set_input_attachments(),
requested: num_input_attachments.total,
});
}
for pc_id in 0 .. desc.num_push_constants_ranges() {
let PipelineLayoutDescPcRange { offset, size, .. } = {
match desc.push_constants_range(pc_id) {
Some(o) => o,
None => continue,
}
};
if offset + size > limits.max_push_constants_size() as usize {
return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
limit: limits.max_push_constants_size() as usize,
requested: offset + size,
});
}
}
Ok(())
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PipelineLayoutLimitsError {
MaxDescriptorSetsLimitExceeded {
limit: usize,
requested: usize,
},
MaxPushConstantsSizeExceeded {
limit: usize,
requested: usize,
},
MaxPerStageResourcesLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorSamplersLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorUniformBuffersLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorStorageBuffersLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorSampledImagesLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorStorageImagesLimitExceeded {
limit: u32,
requested: u32,
},
MaxPerStageDescriptorInputAttachmentsLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetSamplersLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetUniformBuffersLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetStorageBuffersLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetSampledImagesLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetStorageImagesLimitExceeded {
limit: u32,
requested: u32,
},
MaxDescriptorSetInputAttachmentsLimitExceeded {
limit: u32,
requested: u32,
},
}
impl error::Error for PipelineLayoutLimitsError {
#[inline]
fn description(&self) -> &str {
match *self {
PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded { .. } => {
"the maximum number of descriptor sets has been exceeded"
},
PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded { .. } => {
"the maximum size of push constants has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded { .. } => {
"the `max_per_stage_resources()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded { .. } => {
"the `max_per_stage_descriptor_samplers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_storage_buffers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_sampled_images()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_storage_images()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_input_attachments()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded { .. } => {
"the `max_descriptor_set_samplers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded { .. } => {
"the `max_descriptor_set_uniform_buffers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
..
} => {
"the `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded { .. } => {
"the `max_descriptor_set_storage_buffers()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
..
} => {
"the `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded { .. } => {
"the `max_descriptor_set_sampled_images()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded { .. } => {
"the `max_descriptor_set_storage_images()` limit has been exceeded"
},
PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded { .. } => {
"the `max_descriptor_set_input_attachments()` limit has been exceeded"
},
}
}
}
impl fmt::Display for PipelineLayoutLimitsError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
#[derive(Default)]
struct Counter {
total: u32,
compute: u32,
vertex: u32,
geometry: u32,
tess_ctl: u32,
tess_eval: u32,
frag: u32,
}
impl Counter {
fn increment(&mut self, num: u32, stages: &ShaderStages) {
self.total += num;
if stages.compute {
self.compute += num;
}
if stages.vertex {
self.vertex += num;
}
if stages.tessellation_control {
self.tess_ctl += num;
}
if stages.tessellation_evaluation {
self.tess_eval += num;
}
if stages.geometry {
self.geometry += num;
}
if stages.fragment {
self.frag += num;
}
}
fn max_per_stage(&self) -> u32 {
let mut max = 0;
if self.compute > max {
max = self.compute;
}
if self.vertex > max {
max = self.vertex;
}
if self.geometry > max {
max = self.geometry;
}
if self.tess_ctl > max {
max = self.tess_ctl;
}
if self.tess_eval > max {
max = self.tess_eval;
}
if self.frag > max {
max = self.frag;
}
max
}
}