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 use super::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType};
11 use crate::{
12 buffer::{view::BufferView, BufferUsage, Subbuffer},
13 device::DeviceOwned,
14 image::{view::ImageViewType, ImageAspects, ImageType, ImageUsage, ImageViewAbstract},
15 sampler::{Sampler, SamplerImageViewIncompatibleError},
16 DeviceSize, RequiresOneOf, VulkanObject,
17 };
18 use smallvec::SmallVec;
19 use std::{
20 error::Error,
21 fmt::{Display, Error as FmtError, Formatter},
22 ops::Range,
23 ptr,
24 sync::Arc,
25 };
26
27 /// Represents a single write operation to the binding of a descriptor set.
28 ///
29 /// `WriteDescriptorSet` specifies the binding number and target array index, and includes one or
30 /// more resources of a given type that need to be written to that location. Two constructors are
31 /// provided for each resource type:
32 /// - The basic constructor variant writes a single element to array index 0. It is intended for
33 /// non-arrayed bindings, where `descriptor_count` in the descriptor set layout is 1.
34 /// - The `_array` variant writes several elements and allows specifying the target array index.
35 /// At least one element must be provided; a panic results if the provided iterator is empty.
36 pub struct WriteDescriptorSet {
37 binding: u32,
38 first_array_element: u32,
39 elements: WriteDescriptorSetElements,
40 }
41
42 impl WriteDescriptorSet {
43 /// Write an empty element to array element 0.
44 ///
45 /// This is used for push descriptors in combination with `Sampler` descriptors that have
46 /// immutable samplers in the layout. The Vulkan spec requires these elements to be explicitly
47 /// written, but since there is no data to write, a dummy write is provided instead.
48 ///
49 /// For regular descriptor sets, the data for such descriptors is automatically valid, and dummy
50 /// writes are not allowed.
51 #[inline]
none(binding: u32) -> Self52 pub fn none(binding: u32) -> Self {
53 Self::none_array(binding, 0, 1)
54 }
55
56 /// Write a number of consecutive empty elements.
57 ///
58 /// See [`none`](Self::none) for more information.
59 #[inline]
none_array(binding: u32, first_array_element: u32, num_elements: u32) -> Self60 pub fn none_array(binding: u32, first_array_element: u32, num_elements: u32) -> Self {
61 assert!(num_elements != 0);
62 Self {
63 binding,
64 first_array_element,
65 elements: WriteDescriptorSetElements::None(num_elements),
66 }
67 }
68
69 /// Write a single buffer to array element 0, with the bound range covering the whole buffer.
70 ///
71 /// For dynamic buffer bindings, this will bind the whole buffer, and only a dynamic offset
72 /// of zero will be valid, which is probably not what you want.
73 /// Use [`buffer_with_range`](Self::buffer_with_range) instead.
74 #[inline]
buffer(binding: u32, buffer: Subbuffer<impl ?Sized>) -> Self75 pub fn buffer(binding: u32, buffer: Subbuffer<impl ?Sized>) -> Self {
76 let range = 0..buffer.size();
77 Self::buffer_with_range_array(binding, 0, [(buffer, range)])
78 }
79
80 /// Write a number of consecutive buffer elements.
81 ///
82 /// See [`buffer`](Self::buffer) for more information.
83 #[inline]
buffer_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = Subbuffer<impl ?Sized>>, ) -> Self84 pub fn buffer_array(
85 binding: u32,
86 first_array_element: u32,
87 elements: impl IntoIterator<Item = Subbuffer<impl ?Sized>>,
88 ) -> Self {
89 Self::buffer_with_range_array(
90 binding,
91 first_array_element,
92 elements.into_iter().map(|buffer| {
93 let range = 0..buffer.size();
94 (buffer, range)
95 }),
96 )
97 }
98
99 /// Write a single buffer to array element 0, specifying the range of the buffer to be bound.
100 ///
101 /// `range` is the slice of bytes in `buffer` that will be made available to the shader.
102 /// `range` must not be outside the range `buffer`.
103 ///
104 /// For dynamic buffer bindings, `range` specifies the slice that is to be bound if the
105 /// dynamic offset were zero. When binding the descriptor set, the effective value of `range`
106 /// shifts forward by the offset that was provided. For example, if `range` is specified as
107 /// `0..8` when writing the descriptor set, and then when binding the descriptor set the
108 /// offset `16` is used, then the range of `buffer` that will actually be bound is `16..24`.
109 #[inline]
buffer_with_range( binding: u32, buffer: Subbuffer<impl ?Sized>, range: Range<DeviceSize>, ) -> Self110 pub fn buffer_with_range(
111 binding: u32,
112 buffer: Subbuffer<impl ?Sized>,
113 range: Range<DeviceSize>,
114 ) -> Self {
115 Self::buffer_with_range_array(binding, 0, [(buffer, range)])
116 }
117
118 /// Write a number of consecutive buffer elements, specifying the ranges of the buffers to be
119 /// bound.
120 ///
121 /// See [`buffer_with_range`](Self::buffer_with_range) for more information.
buffer_with_range_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = (Subbuffer<impl ?Sized>, Range<DeviceSize>)>, ) -> Self122 pub fn buffer_with_range_array(
123 binding: u32,
124 first_array_element: u32,
125 elements: impl IntoIterator<Item = (Subbuffer<impl ?Sized>, Range<DeviceSize>)>,
126 ) -> Self {
127 let elements: SmallVec<_> = elements
128 .into_iter()
129 .map(|(buffer, range)| (buffer.into_bytes(), range))
130 .collect();
131 assert!(!elements.is_empty());
132
133 Self {
134 binding,
135 first_array_element,
136 elements: WriteDescriptorSetElements::Buffer(elements),
137 }
138 }
139
140 /// Write a single buffer view to array element 0.
141 #[inline]
buffer_view(binding: u32, buffer_view: Arc<BufferView>) -> Self142 pub fn buffer_view(binding: u32, buffer_view: Arc<BufferView>) -> Self {
143 Self::buffer_view_array(binding, 0, [buffer_view])
144 }
145
146 /// Write a number of consecutive buffer view elements.
buffer_view_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = Arc<BufferView>>, ) -> Self147 pub fn buffer_view_array(
148 binding: u32,
149 first_array_element: u32,
150 elements: impl IntoIterator<Item = Arc<BufferView>>,
151 ) -> Self {
152 let elements: SmallVec<_> = elements.into_iter().collect();
153 assert!(!elements.is_empty());
154 Self {
155 binding,
156 first_array_element,
157 elements: WriteDescriptorSetElements::BufferView(elements),
158 }
159 }
160
161 /// Write a single image view to array element 0.
162 #[inline]
image_view(binding: u32, image_view: Arc<dyn ImageViewAbstract>) -> Self163 pub fn image_view(binding: u32, image_view: Arc<dyn ImageViewAbstract>) -> Self {
164 Self::image_view_array(binding, 0, [image_view])
165 }
166
167 /// Write a number of consecutive image view elements.
image_view_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>, ) -> Self168 pub fn image_view_array(
169 binding: u32,
170 first_array_element: u32,
171 elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>,
172 ) -> Self {
173 let elements: SmallVec<_> = elements.into_iter().collect();
174 assert!(!elements.is_empty());
175 Self {
176 binding,
177 first_array_element,
178 elements: WriteDescriptorSetElements::ImageView(elements),
179 }
180 }
181
182 /// Write a single image view and sampler to array element 0.
183 #[inline]
image_view_sampler( binding: u32, image_view: Arc<dyn ImageViewAbstract>, sampler: Arc<Sampler>, ) -> Self184 pub fn image_view_sampler(
185 binding: u32,
186 image_view: Arc<dyn ImageViewAbstract>,
187 sampler: Arc<Sampler>,
188 ) -> Self {
189 Self::image_view_sampler_array(binding, 0, [(image_view, sampler)])
190 }
191
192 /// Write a number of consecutive image view and sampler elements.
image_view_sampler_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>, ) -> Self193 pub fn image_view_sampler_array(
194 binding: u32,
195 first_array_element: u32,
196 elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>,
197 ) -> Self {
198 let elements: SmallVec<_> = elements.into_iter().collect();
199 assert!(!elements.is_empty());
200 Self {
201 binding,
202 first_array_element,
203 elements: WriteDescriptorSetElements::ImageViewSampler(elements),
204 }
205 }
206
207 /// Write a single sampler to array element 0.
208 #[inline]
sampler(binding: u32, sampler: Arc<Sampler>) -> Self209 pub fn sampler(binding: u32, sampler: Arc<Sampler>) -> Self {
210 Self::sampler_array(binding, 0, [sampler])
211 }
212
213 /// Write a number of consecutive sampler elements.
sampler_array( binding: u32, first_array_element: u32, elements: impl IntoIterator<Item = Arc<Sampler>>, ) -> Self214 pub fn sampler_array(
215 binding: u32,
216 first_array_element: u32,
217 elements: impl IntoIterator<Item = Arc<Sampler>>,
218 ) -> Self {
219 let elements: SmallVec<_> = elements.into_iter().collect();
220 assert!(!elements.is_empty());
221 Self {
222 binding,
223 first_array_element,
224 elements: WriteDescriptorSetElements::Sampler(elements),
225 }
226 }
227
228 /// Returns the binding number that is updated by this descriptor write.
229 #[inline]
binding(&self) -> u32230 pub fn binding(&self) -> u32 {
231 self.binding
232 }
233
234 /// Returns the first array element in the binding that is updated by this descriptor write.
235 #[inline]
first_array_element(&self) -> u32236 pub fn first_array_element(&self) -> u32 {
237 self.first_array_element
238 }
239
240 /// Returns a reference to the elements held by this descriptor write.
241 #[inline]
elements(&self) -> &WriteDescriptorSetElements242 pub fn elements(&self) -> &WriteDescriptorSetElements {
243 &self.elements
244 }
245
to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo246 pub(crate) fn to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo {
247 match &self.elements {
248 WriteDescriptorSetElements::None(num_elements) => {
249 debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
250 DescriptorWriteInfo::Image(
251 std::iter::repeat_with(|| ash::vk::DescriptorImageInfo {
252 sampler: ash::vk::Sampler::null(),
253 image_view: ash::vk::ImageView::null(),
254 image_layout: ash::vk::ImageLayout::UNDEFINED,
255 })
256 .take(*num_elements as usize)
257 .collect(),
258 )
259 }
260 WriteDescriptorSetElements::Buffer(elements) => {
261 debug_assert!(matches!(
262 descriptor_type,
263 DescriptorType::UniformBuffer
264 | DescriptorType::StorageBuffer
265 | DescriptorType::UniformBufferDynamic
266 | DescriptorType::StorageBufferDynamic
267 ));
268 DescriptorWriteInfo::Buffer(
269 elements
270 .iter()
271 .map(|(buffer, range)| {
272 debug_assert!(!range.is_empty());
273 debug_assert!(range.end <= buffer.buffer().size());
274
275 ash::vk::DescriptorBufferInfo {
276 buffer: buffer.buffer().handle(),
277 offset: buffer.offset() + range.start,
278 range: range.end - range.start,
279 }
280 })
281 .collect(),
282 )
283 }
284 WriteDescriptorSetElements::BufferView(elements) => {
285 debug_assert!(matches!(
286 descriptor_type,
287 DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer
288 ));
289 DescriptorWriteInfo::BufferView(
290 elements
291 .iter()
292 .map(|buffer_view| buffer_view.handle())
293 .collect(),
294 )
295 }
296 WriteDescriptorSetElements::ImageView(elements) => {
297 // Note: combined image sampler can occur with immutable samplers
298 debug_assert!(matches!(
299 descriptor_type,
300 DescriptorType::CombinedImageSampler
301 | DescriptorType::SampledImage
302 | DescriptorType::StorageImage
303 | DescriptorType::InputAttachment
304 ));
305 DescriptorWriteInfo::Image(
306 elements
307 .iter()
308 .map(|image_view| {
309 let layouts = image_view.image().descriptor_layouts().expect(
310 "descriptor_layouts must return Some when used in an image view",
311 );
312 ash::vk::DescriptorImageInfo {
313 sampler: ash::vk::Sampler::null(),
314 image_view: image_view.handle(),
315 image_layout: layouts.layout_for(descriptor_type).into(),
316 }
317 })
318 .collect(),
319 )
320 }
321 WriteDescriptorSetElements::ImageViewSampler(elements) => {
322 debug_assert!(matches!(
323 descriptor_type,
324 DescriptorType::CombinedImageSampler
325 ));
326 DescriptorWriteInfo::Image(
327 elements
328 .iter()
329 .map(|(image_view, sampler)| {
330 let layouts = image_view.image().descriptor_layouts().expect(
331 "descriptor_layouts must return Some when used in an image view",
332 );
333 ash::vk::DescriptorImageInfo {
334 sampler: sampler.handle(),
335 image_view: image_view.handle(),
336 image_layout: layouts.layout_for(descriptor_type).into(),
337 }
338 })
339 .collect(),
340 )
341 }
342 WriteDescriptorSetElements::Sampler(elements) => {
343 debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
344 DescriptorWriteInfo::Image(
345 elements
346 .iter()
347 .map(|sampler| ash::vk::DescriptorImageInfo {
348 sampler: sampler.handle(),
349 image_view: ash::vk::ImageView::null(),
350 image_layout: ash::vk::ImageLayout::UNDEFINED,
351 })
352 .collect(),
353 )
354 }
355 }
356 }
357
to_vulkan( &self, dst_set: ash::vk::DescriptorSet, descriptor_type: DescriptorType, ) -> ash::vk::WriteDescriptorSet358 pub(crate) fn to_vulkan(
359 &self,
360 dst_set: ash::vk::DescriptorSet,
361 descriptor_type: DescriptorType,
362 ) -> ash::vk::WriteDescriptorSet {
363 ash::vk::WriteDescriptorSet {
364 dst_set,
365 dst_binding: self.binding,
366 dst_array_element: self.first_array_element,
367 descriptor_count: 0,
368 descriptor_type: descriptor_type.into(),
369 p_image_info: ptr::null(),
370 p_buffer_info: ptr::null(),
371 p_texel_buffer_view: ptr::null(),
372 ..Default::default()
373 }
374 }
375 }
376
377 /// The elements held by a `WriteDescriptorSet`.
378 pub enum WriteDescriptorSetElements {
379 None(u32),
380 Buffer(SmallVec<[(Subbuffer<[u8]>, Range<DeviceSize>); 1]>),
381 BufferView(SmallVec<[Arc<BufferView>; 1]>),
382 ImageView(SmallVec<[Arc<dyn ImageViewAbstract>; 1]>),
383 ImageViewSampler(SmallVec<[(Arc<dyn ImageViewAbstract>, Arc<Sampler>); 1]>),
384 Sampler(SmallVec<[Arc<Sampler>; 1]>),
385 }
386
387 impl WriteDescriptorSetElements {
388 /// Returns the number of elements.
389 #[inline]
len(&self) -> u32390 pub fn len(&self) -> u32 {
391 match self {
392 Self::None(num_elements) => *num_elements,
393 Self::Buffer(elements) => elements.len() as u32,
394 Self::BufferView(elements) => elements.len() as u32,
395 Self::ImageView(elements) => elements.len() as u32,
396 Self::ImageViewSampler(elements) => elements.len() as u32,
397 Self::Sampler(elements) => elements.len() as u32,
398 }
399 }
400 }
401
402 #[derive(Clone, Debug)]
403 pub(crate) enum DescriptorWriteInfo {
404 Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
405 Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
406 BufferView(SmallVec<[ash::vk::BufferView; 1]>),
407 }
408
check_descriptor_write<'a>( write: &WriteDescriptorSet, layout: &'a DescriptorSetLayout, variable_descriptor_count: u32, ) -> Result<&'a DescriptorSetLayoutBinding, DescriptorSetUpdateError>409 pub(crate) fn check_descriptor_write<'a>(
410 write: &WriteDescriptorSet,
411 layout: &'a DescriptorSetLayout,
412 variable_descriptor_count: u32,
413 ) -> Result<&'a DescriptorSetLayoutBinding, DescriptorSetUpdateError> {
414 fn provided_element_type(elements: &WriteDescriptorSetElements) -> &'static str {
415 match elements {
416 WriteDescriptorSetElements::None(_) => "none",
417 WriteDescriptorSetElements::Buffer(_) => "buffer",
418 WriteDescriptorSetElements::BufferView(_) => "buffer_view",
419 WriteDescriptorSetElements::ImageView(_) => "image_view",
420 WriteDescriptorSetElements::ImageViewSampler(_) => "image_view_sampler",
421 WriteDescriptorSetElements::Sampler(_) => "sampler",
422 }
423 }
424
425 let device = layout.device();
426
427 let layout_binding = match layout.bindings().get(&write.binding()) {
428 Some(binding) => binding,
429 None => {
430 return Err(DescriptorSetUpdateError::InvalidBinding {
431 binding: write.binding(),
432 })
433 }
434 };
435
436 let max_descriptor_count = if layout_binding.variable_descriptor_count {
437 variable_descriptor_count
438 } else {
439 layout_binding.descriptor_count
440 };
441
442 let binding = write.binding();
443 let elements = write.elements();
444 let num_elements = elements.len();
445 debug_assert!(num_elements != 0);
446
447 let descriptor_range_start = write.first_array_element();
448 let descriptor_range_end = descriptor_range_start + num_elements;
449
450 if descriptor_range_end > max_descriptor_count {
451 return Err(DescriptorSetUpdateError::ArrayIndexOutOfBounds {
452 binding,
453 available_count: max_descriptor_count,
454 written_count: descriptor_range_end,
455 });
456 }
457
458 match layout_binding.descriptor_type {
459 DescriptorType::Sampler => {
460 if layout_binding.immutable_samplers.is_empty() {
461 let elements = if let WriteDescriptorSetElements::Sampler(elements) = elements {
462 elements
463 } else {
464 return Err(DescriptorSetUpdateError::IncompatibleElementType {
465 binding,
466 provided_element_type: provided_element_type(elements),
467 allowed_element_types: &["sampler"],
468 });
469 };
470
471 for (index, sampler) in elements.iter().enumerate() {
472 assert_eq!(device, sampler.device());
473
474 if sampler.sampler_ycbcr_conversion().is_some() {
475 return Err(DescriptorSetUpdateError::SamplerHasSamplerYcbcrConversion {
476 binding: write.binding(),
477 index: descriptor_range_start + index as u32,
478 });
479 }
480 }
481 } else if layout.push_descriptor() {
482 // For push descriptors, we must write a dummy element.
483 if let WriteDescriptorSetElements::None(_) = elements {
484 // Do nothing
485 } else {
486 return Err(DescriptorSetUpdateError::IncompatibleElementType {
487 binding,
488 provided_element_type: provided_element_type(elements),
489 allowed_element_types: &["none"],
490 });
491 }
492 } else {
493 // For regular descriptors, no element must be written.
494 return Err(DescriptorSetUpdateError::IncompatibleElementType {
495 binding,
496 provided_element_type: provided_element_type(elements),
497 allowed_element_types: &[],
498 });
499 }
500 }
501
502 DescriptorType::CombinedImageSampler => {
503 if layout_binding.immutable_samplers.is_empty() {
504 let elements =
505 if let WriteDescriptorSetElements::ImageViewSampler(elements) = elements {
506 elements
507 } else {
508 return Err(DescriptorSetUpdateError::IncompatibleElementType {
509 binding,
510 provided_element_type: provided_element_type(elements),
511 allowed_element_types: &["image_view_sampler"],
512 });
513 };
514
515 for (index, (image_view, sampler)) in elements.iter().enumerate() {
516 assert_eq!(device, image_view.device());
517 assert_eq!(device, sampler.device());
518
519 // VUID-VkWriteDescriptorSet-descriptorType-00337
520 if !image_view.usage().intersects(ImageUsage::SAMPLED) {
521 return Err(DescriptorSetUpdateError::MissingUsage {
522 binding: write.binding(),
523 index: descriptor_range_start + index as u32,
524 usage: "sampled",
525 });
526 }
527
528 // VUID-VkDescriptorImageInfo-imageView-00343
529 if matches!(
530 image_view.view_type(),
531 ImageViewType::Dim2d | ImageViewType::Dim2dArray
532 ) && image_view.image().inner().image.dimensions().image_type()
533 == ImageType::Dim3d
534 {
535 return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
536 binding: write.binding(),
537 index: descriptor_range_start + index as u32,
538 });
539 }
540
541 // VUID-VkDescriptorImageInfo-imageView-01976
542 if image_view
543 .subresource_range()
544 .aspects
545 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
546 {
547 return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
548 binding: write.binding(),
549 index: descriptor_range_start + index as u32,
550 });
551 }
552
553 // VUID-VkDescriptorImageInfo-mutableComparisonSamplers-04450
554 if device.enabled_extensions().khr_portability_subset
555 && !device.enabled_features().mutable_comparison_samplers
556 && sampler.compare().is_some()
557 {
558 return Err(DescriptorSetUpdateError::RequirementNotMet {
559 binding: write.binding(),
560 index: descriptor_range_start + index as u32,
561 required_for: "this device is a portability subset device, and \
562 `sampler.compare()` is `Some`",
563 requires_one_of: RequiresOneOf {
564 features: &["mutable_comparison_samplers"],
565 ..Default::default()
566 },
567 });
568 }
569
570 if image_view.sampler_ycbcr_conversion().is_some() {
571 return Err(
572 DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
573 binding: write.binding(),
574 index: descriptor_range_start + index as u32,
575 },
576 );
577 }
578
579 if sampler.sampler_ycbcr_conversion().is_some() {
580 return Err(DescriptorSetUpdateError::SamplerHasSamplerYcbcrConversion {
581 binding: write.binding(),
582 index: descriptor_range_start + index as u32,
583 });
584 }
585
586 if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
587 return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
588 binding: write.binding(),
589 index: descriptor_range_start + index as u32,
590 error,
591 });
592 }
593 }
594 } else {
595 let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
596 elements
597 } else {
598 return Err(DescriptorSetUpdateError::IncompatibleElementType {
599 binding,
600 provided_element_type: provided_element_type(elements),
601 allowed_element_types: &["image_view"],
602 });
603 };
604
605 let immutable_samplers = &layout_binding.immutable_samplers
606 [descriptor_range_start as usize..descriptor_range_end as usize];
607
608 for (index, (image_view, sampler)) in
609 elements.iter().zip(immutable_samplers).enumerate()
610 {
611 assert_eq!(device, image_view.device());
612
613 // VUID-VkWriteDescriptorSet-descriptorType-00337
614 if !image_view.usage().intersects(ImageUsage::SAMPLED) {
615 return Err(DescriptorSetUpdateError::MissingUsage {
616 binding: write.binding(),
617 index: descriptor_range_start + index as u32,
618 usage: "sampled",
619 });
620 }
621
622 // VUID-VkDescriptorImageInfo-imageView-00343
623 if matches!(
624 image_view.view_type(),
625 ImageViewType::Dim2d | ImageViewType::Dim2dArray
626 ) && image_view.image().inner().image.dimensions().image_type()
627 == ImageType::Dim3d
628 {
629 return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
630 binding: write.binding(),
631 index: descriptor_range_start + index as u32,
632 });
633 }
634
635 // VUID-VkDescriptorImageInfo-imageView-01976
636 if image_view
637 .subresource_range()
638 .aspects
639 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
640 {
641 return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
642 binding: write.binding(),
643 index: descriptor_range_start + index as u32,
644 });
645 }
646
647 if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
648 return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
649 binding: write.binding(),
650 index: descriptor_range_start + index as u32,
651 error,
652 });
653 }
654 }
655 }
656 }
657
658 DescriptorType::SampledImage => {
659 let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
660 elements
661 } else {
662 return Err(DescriptorSetUpdateError::IncompatibleElementType {
663 binding,
664 provided_element_type: provided_element_type(elements),
665 allowed_element_types: &["image_view"],
666 });
667 };
668
669 for (index, image_view) in elements.iter().enumerate() {
670 assert_eq!(device, image_view.device());
671
672 // VUID-VkWriteDescriptorSet-descriptorType-00337
673 if !image_view.usage().intersects(ImageUsage::SAMPLED) {
674 return Err(DescriptorSetUpdateError::MissingUsage {
675 binding: write.binding(),
676 index: descriptor_range_start + index as u32,
677 usage: "sampled",
678 });
679 }
680
681 // VUID-VkDescriptorImageInfo-imageView-00343
682 if matches!(
683 image_view.view_type(),
684 ImageViewType::Dim2d | ImageViewType::Dim2dArray
685 ) && image_view.image().inner().image.dimensions().image_type()
686 == ImageType::Dim3d
687 {
688 return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
689 binding: write.binding(),
690 index: descriptor_range_start + index as u32,
691 });
692 }
693
694 // VUID-VkDescriptorImageInfo-imageView-01976
695 if image_view
696 .subresource_range()
697 .aspects
698 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
699 {
700 return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
701 binding: write.binding(),
702 index: descriptor_range_start + index as u32,
703 });
704 }
705
706 // VUID-VkWriteDescriptorSet-descriptorType-01946
707 if image_view.sampler_ycbcr_conversion().is_some() {
708 return Err(
709 DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
710 binding: write.binding(),
711 index: descriptor_range_start + index as u32,
712 },
713 );
714 }
715 }
716 }
717
718 DescriptorType::StorageImage => {
719 let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
720 elements
721 } else {
722 return Err(DescriptorSetUpdateError::IncompatibleElementType {
723 binding,
724 provided_element_type: provided_element_type(elements),
725 allowed_element_types: &["image_view"],
726 });
727 };
728
729 for (index, image_view) in elements.iter().enumerate() {
730 assert_eq!(device, image_view.device());
731
732 // VUID-VkWriteDescriptorSet-descriptorType-00339
733 if !image_view.usage().intersects(ImageUsage::STORAGE) {
734 return Err(DescriptorSetUpdateError::MissingUsage {
735 binding: write.binding(),
736 index: descriptor_range_start + index as u32,
737 usage: "storage",
738 });
739 }
740
741 // VUID-VkDescriptorImageInfo-imageView-00343
742 if matches!(
743 image_view.view_type(),
744 ImageViewType::Dim2d | ImageViewType::Dim2dArray
745 ) && image_view.image().inner().image.dimensions().image_type()
746 == ImageType::Dim3d
747 {
748 return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
749 binding: write.binding(),
750 index: descriptor_range_start + index as u32,
751 });
752 }
753
754 // VUID-VkDescriptorImageInfo-imageView-01976
755 if image_view
756 .subresource_range()
757 .aspects
758 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
759 {
760 return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
761 binding: write.binding(),
762 index: descriptor_range_start + index as u32,
763 });
764 }
765
766 // VUID-VkWriteDescriptorSet-descriptorType-00336
767 if !image_view.component_mapping().is_identity() {
768 return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
769 binding: write.binding(),
770 index: descriptor_range_start + index as u32,
771 });
772 }
773
774 // VUID??
775 if image_view.sampler_ycbcr_conversion().is_some() {
776 return Err(
777 DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
778 binding: write.binding(),
779 index: descriptor_range_start + index as u32,
780 },
781 );
782 }
783 }
784 }
785
786 DescriptorType::UniformTexelBuffer => {
787 let elements = if let WriteDescriptorSetElements::BufferView(elements) = elements {
788 elements
789 } else {
790 return Err(DescriptorSetUpdateError::IncompatibleElementType {
791 binding,
792 provided_element_type: provided_element_type(elements),
793 allowed_element_types: &["buffer_view"],
794 });
795 };
796
797 for (index, buffer_view) in elements.iter().enumerate() {
798 assert_eq!(device, buffer_view.device());
799
800 if !buffer_view
801 .buffer()
802 .buffer()
803 .usage()
804 .intersects(BufferUsage::UNIFORM_TEXEL_BUFFER)
805 {
806 return Err(DescriptorSetUpdateError::MissingUsage {
807 binding: write.binding(),
808 index: descriptor_range_start + index as u32,
809 usage: "uniform_texel_buffer",
810 });
811 }
812 }
813 }
814
815 DescriptorType::StorageTexelBuffer => {
816 let elements = if let WriteDescriptorSetElements::BufferView(elements) = elements {
817 elements
818 } else {
819 return Err(DescriptorSetUpdateError::IncompatibleElementType {
820 binding,
821 provided_element_type: provided_element_type(elements),
822 allowed_element_types: &["buffer_view"],
823 });
824 };
825
826 for (index, buffer_view) in elements.iter().enumerate() {
827 assert_eq!(device, buffer_view.device());
828
829 // TODO: storage_texel_buffer_atomic
830 if !buffer_view
831 .buffer()
832 .buffer()
833 .usage()
834 .intersects(BufferUsage::STORAGE_TEXEL_BUFFER)
835 {
836 return Err(DescriptorSetUpdateError::MissingUsage {
837 binding: write.binding(),
838 index: descriptor_range_start + index as u32,
839 usage: "storage_texel_buffer",
840 });
841 }
842 }
843 }
844
845 DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
846 let elements = if let WriteDescriptorSetElements::Buffer(elements) = elements {
847 elements
848 } else {
849 return Err(DescriptorSetUpdateError::IncompatibleElementType {
850 binding,
851 provided_element_type: provided_element_type(elements),
852 allowed_element_types: &["buffer"],
853 });
854 };
855
856 for (index, (buffer, range)) in elements.iter().enumerate() {
857 assert_eq!(device, buffer.device());
858
859 if !buffer
860 .buffer()
861 .usage()
862 .intersects(BufferUsage::UNIFORM_BUFFER)
863 {
864 return Err(DescriptorSetUpdateError::MissingUsage {
865 binding: write.binding(),
866 index: descriptor_range_start + index as u32,
867 usage: "uniform_buffer",
868 });
869 }
870
871 assert!(!range.is_empty());
872
873 if range.end > buffer.size() {
874 return Err(DescriptorSetUpdateError::RangeOutOfBufferBounds {
875 binding: write.binding(),
876 index: descriptor_range_start + index as u32,
877 range_end: range.end,
878 buffer_size: buffer.size(),
879 });
880 }
881 }
882 }
883
884 DescriptorType::StorageBuffer | DescriptorType::StorageBufferDynamic => {
885 let elements = if let WriteDescriptorSetElements::Buffer(elements) = elements {
886 elements
887 } else {
888 return Err(DescriptorSetUpdateError::IncompatibleElementType {
889 binding,
890 provided_element_type: provided_element_type(elements),
891 allowed_element_types: &["buffer"],
892 });
893 };
894
895 for (index, (buffer, range)) in elements.iter().enumerate() {
896 assert_eq!(device, buffer.device());
897
898 if !buffer
899 .buffer()
900 .usage()
901 .intersects(BufferUsage::STORAGE_BUFFER)
902 {
903 return Err(DescriptorSetUpdateError::MissingUsage {
904 binding: write.binding(),
905 index: descriptor_range_start + index as u32,
906 usage: "storage_buffer",
907 });
908 }
909
910 assert!(!range.is_empty());
911
912 if range.end > buffer.size() {
913 return Err(DescriptorSetUpdateError::RangeOutOfBufferBounds {
914 binding: write.binding(),
915 index: descriptor_range_start + index as u32,
916 range_end: range.end,
917 buffer_size: buffer.size(),
918 });
919 }
920 }
921 }
922
923 DescriptorType::InputAttachment => {
924 let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
925 elements
926 } else {
927 return Err(DescriptorSetUpdateError::IncompatibleElementType {
928 binding,
929 provided_element_type: provided_element_type(elements),
930 allowed_element_types: &["image_view"],
931 });
932 };
933
934 for (index, image_view) in elements.iter().enumerate() {
935 assert_eq!(device, image_view.device());
936
937 // VUID-VkWriteDescriptorSet-descriptorType-00338
938 if !image_view.usage().intersects(ImageUsage::INPUT_ATTACHMENT) {
939 return Err(DescriptorSetUpdateError::MissingUsage {
940 binding: write.binding(),
941 index: descriptor_range_start + index as u32,
942 usage: "input_attachment",
943 });
944 }
945
946 // VUID-VkDescriptorImageInfo-imageView-00343
947 if matches!(
948 image_view.view_type(),
949 ImageViewType::Dim2d | ImageViewType::Dim2dArray
950 ) && image_view.image().inner().image.dimensions().image_type()
951 == ImageType::Dim3d
952 {
953 return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
954 binding: write.binding(),
955 index: descriptor_range_start + index as u32,
956 });
957 }
958
959 // VUID-VkDescriptorImageInfo-imageView-01976
960 if image_view
961 .subresource_range()
962 .aspects
963 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
964 {
965 return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
966 binding: write.binding(),
967 index: descriptor_range_start + index as u32,
968 });
969 }
970
971 // VUID-VkWriteDescriptorSet-descriptorType-00336
972 if !image_view.component_mapping().is_identity() {
973 return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
974 binding: write.binding(),
975 index: descriptor_range_start + index as u32,
976 });
977 }
978
979 // VUID??
980 if image_view.sampler_ycbcr_conversion().is_some() {
981 return Err(
982 DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
983 binding: write.binding(),
984 index: descriptor_range_start + index as u32,
985 },
986 );
987 }
988
989 // VUID??
990 if image_view.view_type().is_arrayed() {
991 return Err(DescriptorSetUpdateError::ImageViewIsArrayed {
992 binding: write.binding(),
993 index: descriptor_range_start + index as u32,
994 });
995 }
996 }
997 }
998 }
999
1000 Ok(layout_binding)
1001 }
1002
1003 #[derive(Clone, Copy, Debug)]
1004 pub enum DescriptorSetUpdateError {
1005 RequirementNotMet {
1006 binding: u32,
1007 index: u32,
1008 required_for: &'static str,
1009 requires_one_of: RequiresOneOf,
1010 },
1011
1012 /// Tried to write more elements than were available in a binding.
1013 ArrayIndexOutOfBounds {
1014 /// Binding that is affected.
1015 binding: u32,
1016 /// Number of available descriptors in the binding.
1017 available_count: u32,
1018 /// The number of descriptors that were in the update.
1019 written_count: u32,
1020 },
1021
1022 /// Tried to write an image view with a 2D type and a 3D underlying image.
1023 ImageView2dFrom3d { binding: u32, index: u32 },
1024
1025 /// Tried to write an image view that has both the `depth` and `stencil` aspects.
1026 ImageViewDepthAndStencil { binding: u32, index: u32 },
1027
1028 /// Tried to write an image view with an attached sampler YCbCr conversion to a binding that
1029 /// does not support it.
1030 ImageViewHasSamplerYcbcrConversion { binding: u32, index: u32 },
1031
1032 /// Tried to write an image view of an arrayed type to a descriptor type that does not support
1033 /// it.
1034 ImageViewIsArrayed { binding: u32, index: u32 },
1035
1036 /// Tried to write an image view that was not compatible with the sampler that was provided as
1037 /// part of the update or immutably in the layout.
1038 ImageViewIncompatibleSampler {
1039 binding: u32,
1040 index: u32,
1041 error: SamplerImageViewIncompatibleError,
1042 },
1043
1044 /// Tried to write an image view to a descriptor type that requires it to be identity swizzled,
1045 /// but it was not.
1046 ImageViewNotIdentitySwizzled { binding: u32, index: u32 },
1047
1048 /// Tried to write an element type that was not compatible with the descriptor type in the
1049 /// layout.
1050 IncompatibleElementType {
1051 binding: u32,
1052 provided_element_type: &'static str,
1053 allowed_element_types: &'static [&'static str],
1054 },
1055
1056 /// Tried to write to a nonexistent binding.
1057 InvalidBinding { binding: u32 },
1058
1059 /// A resource was missing a usage flag that was required.
1060 MissingUsage {
1061 binding: u32,
1062 index: u32,
1063 usage: &'static str,
1064 },
1065
1066 /// The end of the provided `range` for a buffer is larger than the size of the buffer.
1067 RangeOutOfBufferBounds {
1068 binding: u32,
1069 index: u32,
1070 range_end: DeviceSize,
1071 buffer_size: DeviceSize,
1072 },
1073
1074 /// Tried to write a sampler that has an attached sampler YCbCr conversion.
1075 SamplerHasSamplerYcbcrConversion { binding: u32, index: u32 },
1076 }
1077
1078 impl Error for DescriptorSetUpdateError {
source(&self) -> Option<&(dyn Error + 'static)>1079 fn source(&self) -> Option<&(dyn Error + 'static)> {
1080 match self {
1081 Self::ImageViewIncompatibleSampler { error, .. } => Some(error),
1082 _ => None,
1083 }
1084 }
1085 }
1086
1087 impl Display for DescriptorSetUpdateError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1088 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1089 match self {
1090 Self::RequirementNotMet {
1091 binding,
1092 index,
1093 required_for,
1094 requires_one_of,
1095 } => write!(
1096 f,
1097 "a requirement on binding {} index {} was not met for: {}; requires one of: {}",
1098 binding, index, required_for, requires_one_of,
1099 ),
1100
1101 Self::ArrayIndexOutOfBounds {
1102 binding,
1103 available_count,
1104 written_count,
1105 } => write!(
1106 f,
1107 "tried to write up to element {} to binding {}, but only {} descriptors are \
1108 available",
1109 written_count, binding, available_count,
1110 ),
1111 Self::ImageView2dFrom3d { binding, index } => write!(
1112 f,
1113 "tried to write an image view to binding {} index {} with a 2D type and a 3D \
1114 underlying image",
1115 binding, index,
1116 ),
1117 Self::ImageViewDepthAndStencil { binding, index } => write!(
1118 f,
1119 "tried to write an image view to binding {} index {} that has both the `depth` and \
1120 `stencil` aspects",
1121 binding, index,
1122 ),
1123 Self::ImageViewHasSamplerYcbcrConversion { binding, index } => write!(
1124 f,
1125 "tried to write an image view to binding {} index {} with an attached sampler \
1126 YCbCr conversion to binding that does not support it",
1127 binding, index,
1128 ),
1129 Self::ImageViewIsArrayed { binding, index } => write!(
1130 f,
1131 "tried to write an image view of an arrayed type to binding {} index {}, but this \
1132 binding has a descriptor type that does not support arrayed image views",
1133 binding, index,
1134 ),
1135 Self::ImageViewIncompatibleSampler { binding, index, .. } => write!(
1136 f,
1137 "tried to write an image view to binding {} index {}, that was not compatible with \
1138 the sampler that was provided as part of the update or immutably in the layout",
1139 binding, index,
1140 ),
1141 Self::ImageViewNotIdentitySwizzled { binding, index } => write!(
1142 f,
1143 "tried to write an image view with non-identity swizzling to binding {} index {}, \
1144 but this binding has a descriptor type that requires it to be identity swizzled",
1145 binding, index,
1146 ),
1147 Self::IncompatibleElementType {
1148 binding,
1149 provided_element_type,
1150 allowed_element_types,
1151 } => write!(
1152 f,
1153 "tried to write a resource to binding {} whose type ({}) was not one of the \
1154 resource types allowed for the descriptor type (",
1155 binding, provided_element_type,
1156 )
1157 .and_then(|_| {
1158 let mut first = true;
1159
1160 for elem_type in *allowed_element_types {
1161 if first {
1162 write!(f, "{}", elem_type)?;
1163 first = false;
1164 } else {
1165 write!(f, ", {}", elem_type)?;
1166 }
1167 }
1168
1169 Ok(())
1170 })
1171 .and_then(|_| write!(f, ") that can be bound to this buffer")),
1172 Self::InvalidBinding { binding } => {
1173 write!(f, "tried to write to a nonexistent binding {}", binding,)
1174 }
1175 Self::MissingUsage {
1176 binding,
1177 index,
1178 usage,
1179 } => write!(
1180 f,
1181 "tried to write a resource to binding {} index {} that did not have the required \
1182 usage {} enabled",
1183 binding, index, usage,
1184 ),
1185 Self::RangeOutOfBufferBounds {
1186 binding,
1187 index,
1188 range_end,
1189 buffer_size,
1190 } => write!(
1191 f,
1192 "the end of the provided `range` for the buffer at binding {} index {} ({:?}) is
1193 larger than the size of the buffer ({})",
1194 binding, index, range_end, buffer_size,
1195 ),
1196 Self::SamplerHasSamplerYcbcrConversion { binding, index } => write!(
1197 f,
1198 "tried to write a sampler to binding {} index {} that has an attached sampler \
1199 YCbCr conversion",
1200 binding, index,
1201 ),
1202 }
1203 }
1204 }
1205