1 // Copyright (c) 2017 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9
10 //! Contains the `check_desc_against_limits` function and the `PipelineLayoutLimitsError` error.
11
12 use crate::descriptor_set::layout::DescriptorSetLayout;
13 use crate::descriptor_set::layout::DescriptorType;
14 use crate::device::Properties;
15 use crate::pipeline::layout::PipelineLayoutPcRange;
16 use crate::pipeline::shader::ShaderStages;
17 use std::error;
18 use std::fmt;
19 use std::sync::Arc;
20
21 /// Checks whether the pipeline layout description fulfills the device limits requirements.
check_desc_against_limits( properties: &Properties, descriptor_set_layouts: &[Arc<DescriptorSetLayout>], push_constants_ranges: &[PipelineLayoutPcRange], ) -> Result<(), PipelineLayoutLimitsError>22 pub fn check_desc_against_limits(
23 properties: &Properties,
24 descriptor_set_layouts: &[Arc<DescriptorSetLayout>],
25 push_constants_ranges: &[PipelineLayoutPcRange],
26 ) -> Result<(), PipelineLayoutLimitsError> {
27 let mut num_resources = Counter::default();
28 let mut num_samplers = Counter::default();
29 let mut num_uniform_buffers = Counter::default();
30 let mut num_uniform_buffers_dynamic = 0;
31 let mut num_storage_buffers = Counter::default();
32 let mut num_storage_buffers_dynamic = 0;
33 let mut num_sampled_images = Counter::default();
34 let mut num_storage_images = Counter::default();
35 let mut num_input_attachments = Counter::default();
36
37 for set in descriptor_set_layouts {
38 for descriptor in (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| d)) {
39 num_resources.increment(descriptor.array_count, &descriptor.stages);
40
41 match descriptor.ty.ty() {
42 // TODO:
43 DescriptorType::Sampler => {
44 num_samplers.increment(descriptor.array_count, &descriptor.stages);
45 }
46 DescriptorType::CombinedImageSampler => {
47 num_samplers.increment(descriptor.array_count, &descriptor.stages);
48 num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
49 }
50 DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
51 num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
52 }
53 DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
54 num_storage_images.increment(descriptor.array_count, &descriptor.stages);
55 }
56 DescriptorType::UniformBuffer => {
57 num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
58 }
59 DescriptorType::UniformBufferDynamic => {
60 num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
61 num_uniform_buffers_dynamic += 1;
62 }
63 DescriptorType::StorageBuffer => {
64 num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
65 }
66 DescriptorType::StorageBufferDynamic => {
67 num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
68 num_storage_buffers_dynamic += 1;
69 }
70 DescriptorType::InputAttachment => {
71 num_input_attachments.increment(descriptor.array_count, &descriptor.stages);
72 }
73 }
74 }
75 }
76
77 if descriptor_set_layouts.len() > properties.max_bound_descriptor_sets as usize {
78 return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
79 limit: properties.max_bound_descriptor_sets as usize,
80 requested: descriptor_set_layouts.len(),
81 });
82 }
83
84 if num_resources.max_per_stage() > properties.max_per_stage_resources {
85 return Err(
86 PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
87 limit: properties.max_per_stage_resources,
88 requested: num_resources.max_per_stage(),
89 },
90 );
91 }
92
93 if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
94 return Err(
95 PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
96 limit: properties.max_per_stage_descriptor_samplers,
97 requested: num_samplers.max_per_stage(),
98 },
99 );
100 }
101 if num_uniform_buffers.max_per_stage()
102 > properties.max_per_stage_descriptor_uniform_buffers
103 {
104 return Err(
105 PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
106 limit: properties.max_per_stage_descriptor_uniform_buffers,
107 requested: num_uniform_buffers.max_per_stage(),
108 },
109 );
110 }
111 if num_storage_buffers.max_per_stage()
112 > properties.max_per_stage_descriptor_storage_buffers
113 {
114 return Err(
115 PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
116 limit: properties.max_per_stage_descriptor_storage_buffers,
117 requested: num_storage_buffers.max_per_stage(),
118 },
119 );
120 }
121 if num_sampled_images.max_per_stage()
122 > properties.max_per_stage_descriptor_sampled_images
123 {
124 return Err(
125 PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
126 limit: properties.max_per_stage_descriptor_sampled_images,
127 requested: num_sampled_images.max_per_stage(),
128 },
129 );
130 }
131 if num_storage_images.max_per_stage()
132 > properties.max_per_stage_descriptor_storage_images
133 {
134 return Err(
135 PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
136 limit: properties.max_per_stage_descriptor_storage_images,
137 requested: num_storage_images.max_per_stage(),
138 },
139 );
140 }
141 if num_input_attachments.max_per_stage()
142 > properties
143 .max_per_stage_descriptor_input_attachments
144 {
145 return Err(
146 PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
147 limit: properties
148 .max_per_stage_descriptor_input_attachments,
149 requested: num_input_attachments.max_per_stage(),
150 },
151 );
152 }
153
154 if num_samplers.total > properties.max_descriptor_set_samplers {
155 return Err(
156 PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
157 limit: properties.max_descriptor_set_samplers,
158 requested: num_samplers.total,
159 },
160 );
161 }
162 if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
163 return Err(
164 PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
165 limit: properties.max_descriptor_set_uniform_buffers,
166 requested: num_uniform_buffers.total,
167 },
168 );
169 }
170 if num_uniform_buffers_dynamic
171 > properties
172 .max_descriptor_set_uniform_buffers_dynamic
173 {
174 return Err(
175 PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
176 limit: properties
177 .max_descriptor_set_uniform_buffers_dynamic,
178 requested: num_uniform_buffers_dynamic,
179 },
180 );
181 }
182 if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
183 return Err(
184 PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
185 limit: properties.max_descriptor_set_storage_buffers,
186 requested: num_storage_buffers.total,
187 },
188 );
189 }
190 if num_storage_buffers_dynamic
191 > properties
192 .max_descriptor_set_storage_buffers_dynamic
193 {
194 return Err(
195 PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
196 limit: properties
197 .max_descriptor_set_storage_buffers_dynamic,
198 requested: num_storage_buffers_dynamic,
199 },
200 );
201 }
202 if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
203 return Err(
204 PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
205 limit: properties.max_descriptor_set_sampled_images,
206 requested: num_sampled_images.total,
207 },
208 );
209 }
210 if num_storage_images.total > properties.max_descriptor_set_storage_images {
211 return Err(
212 PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
213 limit: properties.max_descriptor_set_storage_images,
214 requested: num_storage_images.total,
215 },
216 );
217 }
218 if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
219 return Err(
220 PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
221 limit: properties.max_descriptor_set_input_attachments,
222 requested: num_input_attachments.total,
223 },
224 );
225 }
226
227 for &PipelineLayoutPcRange { offset, size, .. } in push_constants_ranges {
228 if offset + size > properties.max_push_constants_size as usize {
229 return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
230 limit: properties.max_push_constants_size as usize,
231 requested: offset + size,
232 });
233 }
234 }
235
236 Ok(())
237 }
238
239 /// The pipeline layout description isn't compatible with the hardware limits.
240 #[derive(Clone, Debug, PartialEq, Eq)]
241 pub enum PipelineLayoutLimitsError {
242 /// The maximum number of descriptor sets has been exceeded.
243 MaxDescriptorSetsLimitExceeded {
244 /// The limit that must be fulfilled.
245 limit: usize,
246 /// What was requested.
247 requested: usize,
248 },
249
250 /// The maximum size of push constants has been exceeded.
251 MaxPushConstantsSizeExceeded {
252 /// The limit that must be fulfilled.
253 limit: usize,
254 /// What was requested.
255 requested: usize,
256 },
257
258 /// The `max_per_stage_resources()` limit has been exceeded.
259 MaxPerStageResourcesLimitExceeded {
260 /// The limit that must be fulfilled.
261 limit: u32,
262 /// What was requested.
263 requested: u32,
264 },
265
266 /// The `max_per_stage_descriptor_samplers()` limit has been exceeded.
267 MaxPerStageDescriptorSamplersLimitExceeded {
268 /// The limit that must be fulfilled.
269 limit: u32,
270 /// What was requested.
271 requested: u32,
272 },
273
274 /// The `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded.
275 MaxPerStageDescriptorUniformBuffersLimitExceeded {
276 /// The limit that must be fulfilled.
277 limit: u32,
278 /// What was requested.
279 requested: u32,
280 },
281
282 /// The `max_per_stage_descriptor_storage_buffers()` limit has been exceeded.
283 MaxPerStageDescriptorStorageBuffersLimitExceeded {
284 /// The limit that must be fulfilled.
285 limit: u32,
286 /// What was requested.
287 requested: u32,
288 },
289
290 /// The `max_per_stage_descriptor_sampled_images()` limit has been exceeded.
291 MaxPerStageDescriptorSampledImagesLimitExceeded {
292 /// The limit that must be fulfilled.
293 limit: u32,
294 /// What was requested.
295 requested: u32,
296 },
297
298 /// The `max_per_stage_descriptor_storage_images()` limit has been exceeded.
299 MaxPerStageDescriptorStorageImagesLimitExceeded {
300 /// The limit that must be fulfilled.
301 limit: u32,
302 /// What was requested.
303 requested: u32,
304 },
305
306 /// The `max_per_stage_descriptor_input_attachments()` limit has been exceeded.
307 MaxPerStageDescriptorInputAttachmentsLimitExceeded {
308 /// The limit that must be fulfilled.
309 limit: u32,
310 /// What was requested.
311 requested: u32,
312 },
313
314 /// The `max_descriptor_set_samplers()` limit has been exceeded.
315 MaxDescriptorSetSamplersLimitExceeded {
316 /// The limit that must be fulfilled.
317 limit: u32,
318 /// What was requested.
319 requested: u32,
320 },
321
322 /// The `max_descriptor_set_uniform_buffers()` limit has been exceeded.
323 MaxDescriptorSetUniformBuffersLimitExceeded {
324 /// The limit that must be fulfilled.
325 limit: u32,
326 /// What was requested.
327 requested: u32,
328 },
329
330 /// The `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded.
331 MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
332 /// The limit that must be fulfilled.
333 limit: u32,
334 /// What was requested.
335 requested: u32,
336 },
337
338 /// The `max_descriptor_set_storage_buffers()` limit has been exceeded.
339 MaxDescriptorSetStorageBuffersLimitExceeded {
340 /// The limit that must be fulfilled.
341 limit: u32,
342 /// What was requested.
343 requested: u32,
344 },
345
346 /// The `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded.
347 MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
348 /// The limit that must be fulfilled.
349 limit: u32,
350 /// What was requested.
351 requested: u32,
352 },
353
354 /// The `max_descriptor_set_sampled_images()` limit has been exceeded.
355 MaxDescriptorSetSampledImagesLimitExceeded {
356 /// The limit that must be fulfilled.
357 limit: u32,
358 /// What was requested.
359 requested: u32,
360 },
361
362 /// The `max_descriptor_set_storage_images()` limit has been exceeded.
363 MaxDescriptorSetStorageImagesLimitExceeded {
364 /// The limit that must be fulfilled.
365 limit: u32,
366 /// What was requested.
367 requested: u32,
368 },
369
370 /// The `max_descriptor_set_input_attachments()` limit has been exceeded.
371 MaxDescriptorSetInputAttachmentsLimitExceeded {
372 /// The limit that must be fulfilled.
373 limit: u32,
374 /// What was requested.
375 requested: u32,
376 },
377 }
378
379 impl error::Error for PipelineLayoutLimitsError {}
380
381 impl fmt::Display for PipelineLayoutLimitsError {
382 #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>383 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
384 write!(
385 fmt,
386 "{}",
387 match *self {
388 PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded { .. } => {
389 "the maximum number of descriptor sets has been exceeded"
390 }
391 PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded { .. } => {
392 "the maximum size of push constants has been exceeded"
393 }
394 PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded { .. } => {
395 "the `max_per_stage_resources()` limit has been exceeded"
396 }
397 PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
398 ..
399 } => {
400 "the `max_per_stage_descriptor_samplers()` limit has been exceeded"
401 }
402 PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
403 ..
404 } => "the `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded",
405 PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
406 ..
407 } => "the `max_per_stage_descriptor_storage_buffers()` limit has been exceeded",
408 PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
409 ..
410 } => "the `max_per_stage_descriptor_sampled_images()` limit has been exceeded",
411 PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
412 ..
413 } => "the `max_per_stage_descriptor_storage_images()` limit has been exceeded",
414 PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
415 ..
416 } => "the `max_per_stage_descriptor_input_attachments()` limit has been exceeded",
417 PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded { .. } => {
418 "the `max_descriptor_set_samplers()` limit has been exceeded"
419 }
420 PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
421 ..
422 } => {
423 "the `max_descriptor_set_uniform_buffers()` limit has been exceeded"
424 }
425 PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
426 ..
427 } => "the `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded",
428 PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
429 ..
430 } => {
431 "the `max_descriptor_set_storage_buffers()` limit has been exceeded"
432 }
433 PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
434 ..
435 } => "the `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded",
436 PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
437 ..
438 } => {
439 "the `max_descriptor_set_sampled_images()` limit has been exceeded"
440 }
441 PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
442 ..
443 } => {
444 "the `max_descriptor_set_storage_images()` limit has been exceeded"
445 }
446 PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
447 ..
448 } => {
449 "the `max_descriptor_set_input_attachments()` limit has been exceeded"
450 }
451 }
452 )
453 }
454 }
455
456 // Helper struct for the main function.
457 #[derive(Default)]
458 struct Counter {
459 total: u32,
460 compute: u32,
461 vertex: u32,
462 geometry: u32,
463 tess_ctl: u32,
464 tess_eval: u32,
465 frag: u32,
466 }
467
468 impl Counter {
increment(&mut self, num: u32, stages: &ShaderStages)469 fn increment(&mut self, num: u32, stages: &ShaderStages) {
470 self.total += num;
471 if stages.compute {
472 self.compute += num;
473 }
474 if stages.vertex {
475 self.vertex += num;
476 }
477 if stages.tessellation_control {
478 self.tess_ctl += num;
479 }
480 if stages.tessellation_evaluation {
481 self.tess_eval += num;
482 }
483 if stages.geometry {
484 self.geometry += num;
485 }
486 if stages.fragment {
487 self.frag += num;
488 }
489 }
490
max_per_stage(&self) -> u32491 fn max_per_stage(&self) -> u32 {
492 let mut max = 0;
493 if self.compute > max {
494 max = self.compute;
495 }
496 if self.vertex > max {
497 max = self.vertex;
498 }
499 if self.geometry > max {
500 max = self.geometry;
501 }
502 if self.tess_ctl > max {
503 max = self.tess_ctl;
504 }
505 if self.tess_eval > max {
506 max = self.tess_eval;
507 }
508 if self.frag > max {
509 max = self.frag;
510 }
511 max
512 }
513 }
514