aboutsummaryrefslogtreecommitdiff
path: root/src/pipeline/layout/limits_check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/pipeline/layout/limits_check.rs')
-rw-r--r--src/pipeline/layout/limits_check.rs513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/pipeline/layout/limits_check.rs b/src/pipeline/layout/limits_check.rs
new file mode 100644
index 0000000..8f98f26
--- /dev/null
+++ b/src/pipeline/layout/limits_check.rs
@@ -0,0 +1,513 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Contains the `check_desc_against_limits` function and the `PipelineLayoutLimitsError` error.
+
+use crate::descriptor_set::layout::DescriptorSetLayout;
+use crate::descriptor_set::layout::DescriptorType;
+use crate::device::Properties;
+use crate::pipeline::layout::PipelineLayoutPcRange;
+use crate::pipeline::shader::ShaderStages;
+use std::error;
+use std::fmt;
+use std::sync::Arc;
+
+/// Checks whether the pipeline layout description fulfills the device limits requirements.
+pub fn check_desc_against_limits(
+ properties: &Properties,
+ descriptor_set_layouts: &[Arc<DescriptorSetLayout>],
+ push_constants_ranges: &[PipelineLayoutPcRange],
+) -> Result<(), PipelineLayoutLimitsError> {
+ 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 descriptor_set_layouts {
+ for descriptor in (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| d)) {
+ num_resources.increment(descriptor.array_count, &descriptor.stages);
+
+ match descriptor.ty.ty() {
+ // TODO:
+ 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 descriptor_set_layouts.len() > properties.max_bound_descriptor_sets as usize {
+ return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
+ limit: properties.max_bound_descriptor_sets as usize,
+ requested: descriptor_set_layouts.len(),
+ });
+ }
+
+ if num_resources.max_per_stage() > properties.max_per_stage_resources {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
+ limit: properties.max_per_stage_resources,
+ requested: num_resources.max_per_stage(),
+ },
+ );
+ }
+
+ if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
+ limit: properties.max_per_stage_descriptor_samplers,
+ requested: num_samplers.max_per_stage(),
+ },
+ );
+ }
+ if num_uniform_buffers.max_per_stage()
+ > properties.max_per_stage_descriptor_uniform_buffers
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
+ limit: properties.max_per_stage_descriptor_uniform_buffers,
+ requested: num_uniform_buffers.max_per_stage(),
+ },
+ );
+ }
+ if num_storage_buffers.max_per_stage()
+ > properties.max_per_stage_descriptor_storage_buffers
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
+ limit: properties.max_per_stage_descriptor_storage_buffers,
+ requested: num_storage_buffers.max_per_stage(),
+ },
+ );
+ }
+ if num_sampled_images.max_per_stage()
+ > properties.max_per_stage_descriptor_sampled_images
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
+ limit: properties.max_per_stage_descriptor_sampled_images,
+ requested: num_sampled_images.max_per_stage(),
+ },
+ );
+ }
+ if num_storage_images.max_per_stage()
+ > properties.max_per_stage_descriptor_storage_images
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
+ limit: properties.max_per_stage_descriptor_storage_images,
+ requested: num_storage_images.max_per_stage(),
+ },
+ );
+ }
+ if num_input_attachments.max_per_stage()
+ > properties
+ .max_per_stage_descriptor_input_attachments
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
+ limit: properties
+ .max_per_stage_descriptor_input_attachments,
+ requested: num_input_attachments.max_per_stage(),
+ },
+ );
+ }
+
+ if num_samplers.total > properties.max_descriptor_set_samplers {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
+ limit: properties.max_descriptor_set_samplers,
+ requested: num_samplers.total,
+ },
+ );
+ }
+ if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
+ limit: properties.max_descriptor_set_uniform_buffers,
+ requested: num_uniform_buffers.total,
+ },
+ );
+ }
+ if num_uniform_buffers_dynamic
+ > properties
+ .max_descriptor_set_uniform_buffers_dynamic
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
+ limit: properties
+ .max_descriptor_set_uniform_buffers_dynamic,
+ requested: num_uniform_buffers_dynamic,
+ },
+ );
+ }
+ if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
+ limit: properties.max_descriptor_set_storage_buffers,
+ requested: num_storage_buffers.total,
+ },
+ );
+ }
+ if num_storage_buffers_dynamic
+ > properties
+ .max_descriptor_set_storage_buffers_dynamic
+ {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
+ limit: properties
+ .max_descriptor_set_storage_buffers_dynamic,
+ requested: num_storage_buffers_dynamic,
+ },
+ );
+ }
+ if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
+ limit: properties.max_descriptor_set_sampled_images,
+ requested: num_sampled_images.total,
+ },
+ );
+ }
+ if num_storage_images.total > properties.max_descriptor_set_storage_images {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
+ limit: properties.max_descriptor_set_storage_images,
+ requested: num_storage_images.total,
+ },
+ );
+ }
+ if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
+ return Err(
+ PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
+ limit: properties.max_descriptor_set_input_attachments,
+ requested: num_input_attachments.total,
+ },
+ );
+ }
+
+ for &PipelineLayoutPcRange { offset, size, .. } in push_constants_ranges {
+ if offset + size > properties.max_push_constants_size as usize {
+ return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
+ limit: properties.max_push_constants_size as usize,
+ requested: offset + size,
+ });
+ }
+ }
+
+ Ok(())
+}
+
+/// The pipeline layout description isn't compatible with the hardware limits.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PipelineLayoutLimitsError {
+ /// The maximum number of descriptor sets has been exceeded.
+ MaxDescriptorSetsLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: usize,
+ /// What was requested.
+ requested: usize,
+ },
+
+ /// The maximum size of push constants has been exceeded.
+ MaxPushConstantsSizeExceeded {
+ /// The limit that must be fulfilled.
+ limit: usize,
+ /// What was requested.
+ requested: usize,
+ },
+
+ /// The `max_per_stage_resources()` limit has been exceeded.
+ MaxPerStageResourcesLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_samplers()` limit has been exceeded.
+ MaxPerStageDescriptorSamplersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded.
+ MaxPerStageDescriptorUniformBuffersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_storage_buffers()` limit has been exceeded.
+ MaxPerStageDescriptorStorageBuffersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_sampled_images()` limit has been exceeded.
+ MaxPerStageDescriptorSampledImagesLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_storage_images()` limit has been exceeded.
+ MaxPerStageDescriptorStorageImagesLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_per_stage_descriptor_input_attachments()` limit has been exceeded.
+ MaxPerStageDescriptorInputAttachmentsLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_samplers()` limit has been exceeded.
+ MaxDescriptorSetSamplersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_uniform_buffers()` limit has been exceeded.
+ MaxDescriptorSetUniformBuffersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded.
+ MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_storage_buffers()` limit has been exceeded.
+ MaxDescriptorSetStorageBuffersLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded.
+ MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_sampled_images()` limit has been exceeded.
+ MaxDescriptorSetSampledImagesLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_storage_images()` limit has been exceeded.
+ MaxDescriptorSetStorageImagesLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+
+ /// The `max_descriptor_set_input_attachments()` limit has been exceeded.
+ MaxDescriptorSetInputAttachmentsLimitExceeded {
+ /// The limit that must be fulfilled.
+ limit: u32,
+ /// What was requested.
+ requested: u32,
+ },
+}
+
+impl error::Error for PipelineLayoutLimitsError {}
+
+impl fmt::Display for PipelineLayoutLimitsError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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"
+ }
+ }
+ )
+ }
+}
+
+// Helper struct for the main function.
+#[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
+ }
+}