vulkano/command_buffer/commands/
render_pass.rs

1use crate::{
2    command_buffer::{
3        auto::{
4            BeginRenderPassState, BeginRenderingState, RenderPassState, RenderPassStateAttachments,
5            RenderPassStateType, Resource,
6        },
7        sys::RecordingCommandBuffer,
8        AutoCommandBufferBuilder, CommandBufferLevel, ResourceInCommand, SubpassContents,
9    },
10    device::{Device, DeviceOwned, QueueFlags},
11    format::{ClearColorValue, ClearValue, NumericType},
12    image::{view::ImageView, ImageAspects, ImageLayout, ImageUsage, SampleCount},
13    pipeline::graphics::subpass::PipelineRenderingCreateInfo,
14    render_pass::{
15        AttachmentDescription, AttachmentLoadOp, AttachmentStoreOp, Framebuffer, RenderPass,
16        ResolveMode, SubpassDescription,
17    },
18    sync::PipelineStageAccessFlags,
19    Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, VulkanObject,
20};
21use smallvec::SmallVec;
22use std::{cmp::min, ops::Range, sync::Arc};
23
24/// # Commands for render passes.
25///
26/// These commands require a graphics queue.
27impl<L> AutoCommandBufferBuilder<L> {
28    /// Begins a render pass using a render pass object and framebuffer.
29    ///
30    /// You must call this or `begin_rendering` before you can record draw commands.
31    ///
32    /// `contents` specifies what kinds of commands will be recorded in the render pass, either
33    /// draw commands or executions of secondary command buffers.
34    pub fn begin_render_pass(
35        &mut self,
36        render_pass_begin_info: RenderPassBeginInfo,
37        subpass_begin_info: SubpassBeginInfo,
38    ) -> Result<&mut Self, Box<ValidationError>> {
39        self.validate_begin_render_pass(&render_pass_begin_info, &subpass_begin_info)?;
40
41        Ok(unsafe { self.begin_render_pass_unchecked(render_pass_begin_info, subpass_begin_info) })
42    }
43
44    fn validate_begin_render_pass(
45        &self,
46        render_pass_begin_info: &RenderPassBeginInfo,
47        subpass_begin_info: &SubpassBeginInfo,
48    ) -> Result<(), Box<ValidationError>> {
49        self.inner
50            .validate_begin_render_pass(render_pass_begin_info, subpass_begin_info)?;
51
52        if self.builder_state.render_pass.is_some() {
53            return Err(Box::new(ValidationError {
54                problem: "a render pass instance is already active".into(),
55                vuids: &["VUID-vkCmdBeginRenderPass2-renderpass"],
56                ..Default::default()
57            }));
58        }
59
60        // VUID-vkCmdBeginRenderPass2-initialLayout-03100
61        // TODO:
62
63        // VUID-vkCmdBeginRenderPass2-srcStageMask-06453
64        // TODO:
65
66        // VUID-vkCmdBeginRenderPass2-dstStageMask-06454
67        // TODO:
68
69        // VUID-vkCmdBeginRenderPass2-framebuffer-02533
70        // For any attachment in framebuffer that is used by renderPass and is bound to memory
71        // locations that are also bound to another attachment used by renderPass, and if at least
72        // one of those uses causes either attachment to be written to, both attachments
73        // must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set
74
75        Ok(())
76    }
77
78    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
79    pub unsafe fn begin_render_pass_unchecked(
80        &mut self,
81        render_pass_begin_info: RenderPassBeginInfo,
82        subpass_begin_info: SubpassBeginInfo,
83    ) -> &mut Self {
84        let &RenderPassBeginInfo {
85            ref render_pass,
86            ref framebuffer,
87            render_area_offset,
88            render_area_extent,
89            clear_values: _,
90            _ne: _,
91        } = &render_pass_begin_info;
92
93        let subpass = render_pass.clone().first_subpass();
94        self.builder_state.render_pass = Some(RenderPassState {
95            contents: subpass_begin_info.contents,
96            render_area_offset,
97            render_area_extent,
98
99            rendering_info: PipelineRenderingCreateInfo::from_subpass(&subpass),
100            attachments: Some(RenderPassStateAttachments::from_subpass(
101                &subpass,
102                framebuffer,
103            )),
104
105            render_pass: BeginRenderPassState {
106                subpass,
107                framebuffer: Some(framebuffer.clone()),
108            }
109            .into(),
110        });
111
112        self.add_render_pass_begin(
113            "begin_render_pass",
114            render_pass
115                .attachments()
116                .iter()
117                .enumerate()
118                .map(|(index, desc)| {
119                    let image_view = &framebuffer.attachments()[index];
120                    let index = index as u32;
121
122                    (
123                        ResourceInCommand::FramebufferAttachment { index }.into(),
124                        Resource::Image {
125                            image: image_view.image().clone(),
126                            subresource_range: image_view.subresource_range().clone(),
127                            // TODO: suboptimal
128                            memory_access: PipelineStageAccessFlags::FragmentShader_InputAttachmentRead
129                                | PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentRead
130                                | PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentWrite
131                                | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentRead
132                                | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentWrite
133                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentRead
134                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentWrite,
135                            start_layout: desc.initial_layout,
136                            end_layout: desc.final_layout,
137                        },
138                    )
139                })
140                .collect(),
141            move |out: &mut RecordingCommandBuffer| {
142                unsafe { out.begin_render_pass_unchecked(&render_pass_begin_info, &subpass_begin_info) };
143            },
144        );
145
146        self
147    }
148
149    /// Advances to the next subpass of the render pass previously begun with `begin_render_pass`.
150    pub fn next_subpass(
151        &mut self,
152        subpass_end_info: SubpassEndInfo,
153        subpass_begin_info: SubpassBeginInfo,
154    ) -> Result<&mut Self, Box<ValidationError>> {
155        self.validate_next_subpass(&subpass_end_info, &subpass_begin_info)?;
156
157        Ok(unsafe { self.next_subpass_unchecked(subpass_end_info, subpass_begin_info) })
158    }
159
160    fn validate_next_subpass(
161        &self,
162        subpass_end_info: &SubpassEndInfo,
163        subpass_begin_info: &SubpassBeginInfo,
164    ) -> Result<(), Box<ValidationError>> {
165        self.inner
166            .validate_next_subpass(subpass_end_info, subpass_begin_info)?;
167
168        let render_pass_state = self.builder_state.render_pass.as_ref().ok_or_else(|| {
169            Box::new(ValidationError {
170                problem: "a render pass instance is not active".into(),
171                vuids: &["VUID-vkCmdNextSubpass2-renderpass"],
172                ..Default::default()
173            })
174        })?;
175
176        let begin_render_pass_state = match &render_pass_state.render_pass {
177            RenderPassStateType::BeginRenderPass(state) => state,
178            RenderPassStateType::BeginRendering(_) => {
179                return Err(Box::new(ValidationError {
180                    problem: "the current render pass instance was not begun with \
181                        `begin_render_pass`"
182                        .into(),
183                    // vuids?
184                    ..Default::default()
185                }));
186            }
187        };
188
189        if begin_render_pass_state.subpass.is_last_subpass() {
190            return Err(Box::new(ValidationError {
191                problem: "the current subpass is the last subpass of the render pass".into(),
192                vuids: &["VUID-vkCmdNextSubpass2-None-03102"],
193                ..Default::default()
194            }));
195        }
196
197        if self
198            .builder_state
199            .queries
200            .values()
201            .any(|state| state.in_subpass)
202        {
203            return Err(Box::new(ValidationError {
204                problem: "a query that was begun in the current subpass is still active".into(),
205                // vuids?
206                ..Default::default()
207            }));
208        }
209
210        Ok(())
211    }
212
213    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
214    pub unsafe fn next_subpass_unchecked(
215        &mut self,
216        subpass_end_info: SubpassEndInfo,
217        subpass_begin_info: SubpassBeginInfo,
218    ) -> &mut Self {
219        let render_pass_state = self.builder_state.render_pass.as_mut().unwrap();
220        let begin_render_pass_state = match &mut render_pass_state.render_pass {
221            RenderPassStateType::BeginRenderPass(x) => x,
222            _ => unreachable!(),
223        };
224
225        begin_render_pass_state.subpass.next_subpass();
226        render_pass_state.contents = subpass_begin_info.contents;
227        render_pass_state.rendering_info =
228            PipelineRenderingCreateInfo::from_subpass(&begin_render_pass_state.subpass);
229        render_pass_state.attachments = Some(RenderPassStateAttachments::from_subpass(
230            &begin_render_pass_state.subpass,
231            begin_render_pass_state.framebuffer.as_ref().unwrap(),
232        ));
233
234        if render_pass_state.rendering_info.view_mask != 0 {
235            // When multiview is enabled, at the beginning of each subpass, all
236            // non-render pass state is undefined.
237            self.builder_state.reset_non_render_pass_states();
238        }
239
240        self.add_command(
241            "next_subpass",
242            Default::default(),
243            move |out: &mut RecordingCommandBuffer| {
244                unsafe { out.next_subpass_unchecked(&subpass_end_info, &subpass_begin_info) };
245            },
246        );
247
248        self
249    }
250
251    /// Ends the render pass previously begun with `begin_render_pass`.
252    ///
253    /// This must be called after you went through all the subpasses.
254    pub fn end_render_pass(
255        &mut self,
256        subpass_end_info: SubpassEndInfo,
257    ) -> Result<&mut Self, Box<ValidationError>> {
258        self.validate_end_render_pass(&subpass_end_info)?;
259
260        Ok(unsafe { self.end_render_pass_unchecked(subpass_end_info) })
261    }
262
263    fn validate_end_render_pass(
264        &self,
265        subpass_end_info: &SubpassEndInfo,
266    ) -> Result<(), Box<ValidationError>> {
267        self.inner.validate_end_render_pass(subpass_end_info)?;
268
269        let render_pass_state = self.builder_state.render_pass.as_ref().ok_or_else(|| {
270            Box::new(ValidationError {
271                problem: "a render pass instance is not active".into(),
272                vuids: &["VUID-vkCmdEndRenderPass2-renderpass"],
273                ..Default::default()
274            })
275        })?;
276
277        let begin_render_pass_state = match &render_pass_state.render_pass {
278            RenderPassStateType::BeginRenderPass(state) => state,
279            RenderPassStateType::BeginRendering(_) => {
280                return Err(Box::new(ValidationError {
281                    problem: "the current render pass instance was not begun with \
282                        `begin_render_pass`"
283                        .into(),
284                    vuids: &["VUID-vkCmdEndRenderPass2-None-06171"],
285                    ..Default::default()
286                }));
287            }
288        };
289
290        if !begin_render_pass_state.subpass.is_last_subpass() {
291            return Err(Box::new(ValidationError {
292                problem: "the current subpass is not the last subpass of the render pass".into(),
293                vuids: &["VUID-vkCmdEndRenderPass2-None-03103"],
294                ..Default::default()
295            }));
296        }
297
298        if self
299            .builder_state
300            .queries
301            .values()
302            .any(|state| state.in_subpass)
303        {
304            return Err(Box::new(ValidationError {
305                problem: "a query that was begun in the current subpass is still active".into(),
306                vuids: &["VUID-vkCmdEndRenderPass2-None-07005"],
307                ..Default::default()
308            }));
309        }
310
311        Ok(())
312    }
313
314    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
315    pub unsafe fn end_render_pass_unchecked(
316        &mut self,
317        subpass_end_info: SubpassEndInfo,
318    ) -> &mut Self {
319        self.builder_state.render_pass = None;
320
321        self.add_render_pass_end(
322            "end_render_pass",
323            Default::default(),
324            move |out: &mut RecordingCommandBuffer| {
325                unsafe { out.end_render_pass_unchecked(&subpass_end_info) };
326            },
327        );
328
329        self
330    }
331
332    /// Begins a render pass without a render pass object or framebuffer.
333    ///
334    /// Requires the [`dynamic_rendering`] device feature.
335    ///
336    /// You must call this or `begin_render_pass` before you can record draw commands.
337    ///
338    /// [`dynamic_rendering`]: crate::device::DeviceFeatures::dynamic_rendering
339    pub fn begin_rendering(
340        &mut self,
341        mut rendering_info: RenderingInfo,
342    ) -> Result<&mut Self, Box<ValidationError>> {
343        rendering_info.set_auto_extent_layers();
344        self.validate_begin_rendering(&rendering_info)?;
345
346        Ok(unsafe { self.begin_rendering_unchecked(rendering_info) })
347    }
348
349    fn validate_begin_rendering(
350        &self,
351        rendering_info: &RenderingInfo,
352    ) -> Result<(), Box<ValidationError>> {
353        self.inner.validate_begin_rendering(rendering_info)?;
354
355        if self.builder_state.render_pass.is_some() {
356            return Err(Box::new(ValidationError {
357                problem: "a render pass instance is already active".into(),
358                vuids: &["VUID-vkCmdBeginRendering-renderpass"],
359                ..Default::default()
360            }));
361        }
362
363        Ok(())
364    }
365
366    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
367    pub unsafe fn begin_rendering_unchecked(
368        &mut self,
369        mut rendering_info: RenderingInfo,
370    ) -> &mut Self {
371        rendering_info.set_auto_extent_layers();
372
373        let &RenderingInfo {
374            render_area_offset,
375            render_area_extent,
376            layer_count: _,
377            view_mask: _,
378            ref color_attachments,
379            ref depth_attachment,
380            ref stencil_attachment,
381            contents,
382            _ne,
383        } = &rendering_info;
384
385        self.builder_state.render_pass = Some(RenderPassState {
386            contents,
387            render_area_offset,
388            render_area_extent,
389
390            rendering_info: PipelineRenderingCreateInfo::from_rendering_info(&rendering_info),
391            attachments: Some(RenderPassStateAttachments::from_rendering_info(
392                &rendering_info,
393            )),
394
395            render_pass: BeginRenderingState {
396                pipeline_used: false,
397            }
398            .into(),
399        });
400
401        self.add_render_pass_begin(
402            "begin_rendering",
403            (color_attachments
404                .iter()
405                .enumerate()
406                .filter_map(|(index, attachment_info)| {
407                    attachment_info
408                        .as_ref()
409                        .map(|attachment_info| (index as u32, attachment_info))
410                })
411                .flat_map(|(index, attachment_info)| {
412                    let &RenderingAttachmentInfo {
413                        ref image_view,
414                        image_layout,
415                        ref resolve_info,
416                        load_op: _,
417                        store_op: _,
418                        clear_value: _,
419                        _ne: _,
420                    } = attachment_info;
421
422                    [
423                        Some((
424                            ResourceInCommand::ColorAttachment { index }.into(),
425                            Resource::Image {
426                                image: image_view.image().clone(),
427                                subresource_range: image_view.subresource_range().clone(),
428                                // TODO: suboptimal
429                                memory_access: PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentRead
430                                    | PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentWrite,
431                                start_layout: image_layout,
432                                end_layout: image_layout,
433                            },
434                        )),
435                        resolve_info.as_ref().map(|resolve_info| {
436                            let &RenderingAttachmentResolveInfo {
437                                mode: _,
438                                ref image_view,
439                                image_layout,
440                            } = resolve_info;
441
442                            (
443                                ResourceInCommand::ColorResolveAttachment { index }.into(),
444                                Resource::Image {
445                                    image: image_view.image().clone(),
446                                    subresource_range: image_view.subresource_range().clone(),
447                                    // TODO: suboptimal
448                                    memory_access: PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentRead
449                                        | PipelineStageAccessFlags::ColorAttachmentOutput_ColorAttachmentWrite,
450                                    start_layout: image_layout,
451                                    end_layout: image_layout,
452                                },
453                            )
454                        }),
455                    ]
456                    .into_iter()
457                    .flatten()
458                }))
459            .chain(depth_attachment.iter().flat_map(|attachment_info| {
460                let &RenderingAttachmentInfo {
461                    ref image_view,
462                    image_layout,
463                    ref resolve_info,
464                    load_op: _,
465                    store_op: _,
466                    clear_value: _,
467                    _ne: _,
468                } = attachment_info;
469
470                [
471                    Some((
472                        ResourceInCommand::DepthStencilAttachment.into(),
473                        Resource::Image {
474                            image: image_view.image().clone(),
475                            subresource_range: image_view.subresource_range().clone(),
476                            // TODO: suboptimal
477                            memory_access: PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentRead
478                                | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentWrite
479                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentRead
480                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentWrite,
481                            start_layout: image_layout,
482                            end_layout: image_layout,
483                        },
484                    )),
485                    resolve_info.as_ref().map(|resolve_info| {
486                        let &RenderingAttachmentResolveInfo {
487                            mode: _,
488                            ref image_view,
489                            image_layout,
490                        } = resolve_info;
491
492                        (
493                            ResourceInCommand::DepthStencilResolveAttachment.into(),
494                            Resource::Image {
495                                image: image_view.image().clone(),
496                                subresource_range: image_view.subresource_range().clone(),
497                                // TODO: suboptimal
498                                memory_access: PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentRead
499                                    | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentWrite
500                                    | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentRead
501                                    | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentWrite,
502                                start_layout: image_layout,
503                                end_layout: image_layout,
504                            },
505                        )
506                    }),
507                ]
508                .into_iter()
509                .flatten()
510            }))
511            .chain(stencil_attachment.iter().flat_map(|attachment_info| {
512                let &RenderingAttachmentInfo {
513                    ref image_view,
514                    image_layout,
515                    ref resolve_info,
516                    load_op: _,
517                    store_op: _,
518                    clear_value: _,
519                    _ne: _,
520                } = attachment_info;
521
522                [
523                    Some((
524                        ResourceInCommand::DepthStencilAttachment.into(),
525                        Resource::Image {
526                            image: image_view.image().clone(),
527                            subresource_range: image_view.subresource_range().clone(),
528                            // TODO: suboptimal
529                            memory_access: PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentRead
530                                | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentWrite
531                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentRead
532                                | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentWrite,
533                            start_layout: image_layout,
534                            end_layout: image_layout,
535                        },
536                    )),
537                    resolve_info.as_ref().map(|resolve_info| {
538                        let &RenderingAttachmentResolveInfo {
539                            mode: _,
540                            ref image_view,
541                            image_layout,
542                        } = resolve_info;
543
544                        (
545                            ResourceInCommand::DepthStencilResolveAttachment.into(),
546                            Resource::Image {
547                                image: image_view.image().clone(),
548                                subresource_range: image_view.subresource_range().clone(),
549                                // TODO: suboptimal
550                                memory_access: PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentRead
551                                    | PipelineStageAccessFlags::EarlyFragmentTests_DepthStencilAttachmentWrite
552                                    | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentRead
553                                    | PipelineStageAccessFlags::LateFragmentTests_DepthStencilAttachmentWrite,
554                                start_layout: image_layout,
555                                end_layout: image_layout,
556                            },
557                        )
558                    }),
559                ]
560                .into_iter()
561                .flatten()
562            }))
563            .collect(),
564            move |out: &mut RecordingCommandBuffer| {
565                unsafe { out.begin_rendering_unchecked(&rendering_info) };
566            },
567        );
568
569        self
570    }
571
572    /// Ends the render pass previously begun with `begin_rendering`.
573    pub fn end_rendering(&mut self) -> Result<&mut Self, Box<ValidationError>> {
574        self.validate_end_rendering()?;
575
576        Ok(unsafe { self.end_rendering_unchecked() })
577    }
578
579    fn validate_end_rendering(&self) -> Result<(), Box<ValidationError>> {
580        self.inner.validate_end_rendering()?;
581
582        let render_pass_state = self.builder_state.render_pass.as_ref().ok_or_else(|| {
583            Box::new(ValidationError {
584                problem: "a render pass instance is not active".into(),
585                vuids: &[
586                    "VUID-vkCmdEndRendering-renderpass",
587                    "VUID-vkCmdEndRendering-commandBuffer-06162",
588                ],
589                ..Default::default()
590            })
591        })?;
592
593        match &render_pass_state.render_pass {
594            RenderPassStateType::BeginRenderPass(_) => {
595                return Err(Box::new(ValidationError {
596                    problem: "the current render pass instance was not begun with \
597                        `begin_rendering`"
598                        .into(),
599                    vuids: &["VUID-vkCmdEndRendering-None-06161"],
600                    ..Default::default()
601                }))
602            }
603            RenderPassStateType::BeginRendering(_) => (),
604        }
605
606        if self
607            .builder_state
608            .queries
609            .values()
610            .any(|state| state.in_subpass)
611        {
612            return Err(Box::new(ValidationError {
613                problem: "a query that was begun in the current render pass instance \
614                    is still active"
615                    .into(),
616                vuids: &["VUID-vkCmdEndRendering-None-06999"],
617                ..Default::default()
618            }));
619        }
620
621        Ok(())
622    }
623
624    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
625    pub unsafe fn end_rendering_unchecked(&mut self) -> &mut Self {
626        self.builder_state.render_pass = None;
627
628        self.add_render_pass_end(
629            "end_rendering",
630            Default::default(),
631            move |out: &mut RecordingCommandBuffer| {
632                unsafe { out.end_rendering_unchecked() };
633            },
634        );
635
636        self
637    }
638
639    /// Clears specific regions of specific attachments of the framebuffer.
640    ///
641    /// `attachments` specify the types of attachments and their clear values.
642    /// `rects` specify the regions to clear.
643    ///
644    /// A graphics pipeline must have been bound using
645    /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). And the command must be inside
646    /// render pass.
647    ///
648    /// If the render pass instance this is recorded in uses multiview,
649    /// then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one.
650    ///
651    /// The rectangle area must be inside the render area ranges.
652    pub fn clear_attachments(
653        &mut self,
654        attachments: SmallVec<[ClearAttachment; 4]>,
655        rects: SmallVec<[ClearRect; 4]>,
656    ) -> Result<&mut Self, Box<ValidationError>> {
657        self.validate_clear_attachments(&attachments, &rects)?;
658
659        Ok(unsafe { self.clear_attachments_unchecked(attachments, rects) })
660    }
661
662    fn validate_clear_attachments(
663        &self,
664        attachments: &[ClearAttachment],
665        rects: &[ClearRect],
666    ) -> Result<(), Box<ValidationError>> {
667        self.inner.validate_clear_attachments(attachments, rects)?;
668
669        let render_pass_state = self.builder_state.render_pass.as_ref().ok_or_else(|| {
670            Box::new(ValidationError {
671                problem: "a render pass instance is not active".into(),
672                vuids: &["VUID-vkCmdClearAttachments-renderpass"],
673                ..Default::default()
674            })
675        })?;
676
677        if render_pass_state.contents != SubpassContents::Inline {
678            return Err(Box::new(ValidationError {
679                problem: "the contents of the current subpass instance is not \
680                    `SubpassContents::Inline`"
681                    .into(),
682                // vuids?
683                ..Default::default()
684            }));
685        }
686
687        let mut layer_count = u32::MAX;
688
689        for (clear_index, &clear_attachment) in attachments.iter().enumerate() {
690            match clear_attachment {
691                ClearAttachment::Color {
692                    color_attachment,
693                    clear_value,
694                } => {
695                    let attachment_format = *render_pass_state
696                        .rendering_info
697                        .color_attachment_formats
698                        .get(color_attachment as usize)
699                        .ok_or_else(|| {
700                            Box::new(ValidationError {
701                                context: format!("attachments[{}].color_attachment", clear_index)
702                                    .into(),
703                                problem: "is not less than the number of color attachments in the \
704                                current subpass instance"
705                                    .into(),
706                                vuids: &["VUID-vkCmdClearAttachments-aspectMask-07271"],
707                                ..Default::default()
708                            })
709                        })?;
710
711                    if let Some(attachment_format) = attachment_format {
712                        let required_numeric_type = attachment_format
713                            .numeric_format_color()
714                            .unwrap()
715                            .numeric_type();
716
717                        if clear_value.numeric_type() != required_numeric_type {
718                            return Err(Box::new(ValidationError {
719                                problem: format!(
720                                    "`attachments[{0}].clear_value` is `ClearColorValue::{1:?}`, \
721                                    but the color attachment specified by \
722                                    `attachments[{0}].color_attachment` requires a clear value \
723                                    of type `ClearColorValue::{2:?}`",
724                                    clear_index,
725                                    clear_value.numeric_type(),
726                                    required_numeric_type,
727                                )
728                                .into(),
729                                vuids: &["VUID-vkCmdClearAttachments-aspectMask-02501"],
730                                ..Default::default()
731                            }));
732                        }
733                    }
734
735                    let image_view = render_pass_state
736                        .attachments
737                        .as_ref()
738                        .and_then(|attachments| attachments.depth_attachment.as_ref())
739                        .map(|attachment_info| &attachment_info.image_view);
740
741                    // We only know the layer count if we have a known attachment image.
742                    if let Some(image_view) = image_view {
743                        let array_layers = &image_view.subresource_range().array_layers;
744                        layer_count = min(layer_count, array_layers.end - array_layers.start);
745                    }
746                }
747                ClearAttachment::Depth(_)
748                | ClearAttachment::Stencil(_)
749                | ClearAttachment::DepthStencil(_) => {
750                    if matches!(
751                        clear_attachment,
752                        ClearAttachment::Depth(_) | ClearAttachment::DepthStencil(_)
753                    ) && render_pass_state
754                        .rendering_info
755                        .depth_attachment_format
756                        .is_none()
757                    {
758                        return Err(Box::new(ValidationError {
759                            problem: format!(
760                                "`attachments[{0}]` is `ClearAttachment::Depth` or \
761                                `ClearAttachment::DepthStencil`, but \
762                                the current subpass instance does not have a depth attachment",
763                                clear_index,
764                            )
765                            .into(),
766                            vuids: &["VUID-vkCmdClearAttachments-aspectMask-02502"],
767                            ..Default::default()
768                        }));
769                    }
770
771                    if matches!(
772                        clear_attachment,
773                        ClearAttachment::Stencil(_) | ClearAttachment::DepthStencil(_)
774                    ) && render_pass_state
775                        .rendering_info
776                        .stencil_attachment_format
777                        .is_none()
778                    {
779                        return Err(Box::new(ValidationError {
780                            problem: format!(
781                                "`attachments[{0}]` is `ClearAttachment::Stencil` or \
782                                `ClearAttachment::DepthStencil`, but \
783                                the current subpass instance does not have a stencil attachment",
784                                clear_index,
785                            )
786                            .into(),
787                            vuids: &["VUID-vkCmdClearAttachments-aspectMask-02503"],
788                            ..Default::default()
789                        }));
790                    }
791
792                    let image_view = render_pass_state
793                        .attachments
794                        .as_ref()
795                        .and_then(|attachments| attachments.depth_attachment.as_ref())
796                        .map(|attachment_info| &attachment_info.image_view);
797
798                    // We only know the layer count if we have a known attachment image.
799                    if let Some(image_view) = image_view {
800                        let array_layers = &image_view.subresource_range().array_layers;
801                        layer_count = min(layer_count, array_layers.end - array_layers.start);
802                    }
803                }
804            }
805        }
806
807        for (rect_index, rect) in rects.iter().enumerate() {
808            for i in 0..2 {
809                // TODO: This check will always pass in secondary command buffers because of how
810                // it's set in `with_level`.
811                // It needs to be checked during `execute_commands` instead.
812
813                if rect.offset[i] < render_pass_state.render_area_offset[i] {
814                    return Err(Box::new(ValidationError {
815                        problem: format!(
816                            "`rects[{0}].offset[{i}]` is less than \
817                            `render_area_offset[{i}]` of the current render pass instance",
818                            rect_index
819                        )
820                        .into(),
821                        vuids: &["VUID-vkCmdClearAttachments-pRects-00016"],
822                        ..Default::default()
823                    }));
824                }
825
826                if rect.offset[i] + rect.extent[i]
827                    > render_pass_state.render_area_offset[i]
828                        + render_pass_state.render_area_extent[i]
829                {
830                    return Err(Box::new(ValidationError {
831                        problem: format!(
832                            "`rects[{0}].offset[{i}] + rects[{0}].extent[{i}]` is \
833                            greater than `render_area_offset[{i}] + render_area_extent[{i}]` \
834                            of the current render pass instance",
835                            rect_index,
836                        )
837                        .into(),
838                        vuids: &["VUID-vkCmdClearAttachments-pRects-00016"],
839                        ..Default::default()
840                    }));
841                }
842            }
843
844            if rect.array_layers.end > layer_count {
845                return Err(Box::new(ValidationError {
846                    problem: format!(
847                        "`rects[{}].array_layers.end` is greater than the number of \
848                        array layers in the current render pass instance",
849                        rect_index
850                    )
851                    .into(),
852                    vuids: &["VUID-vkCmdClearAttachments-pRects-06937"],
853                    ..Default::default()
854                }));
855            }
856
857            if render_pass_state.rendering_info.view_mask != 0 && rect.array_layers != (0..1) {
858                return Err(Box::new(ValidationError {
859                    problem: format!(
860                        "the current render pass instance has a non-zero `view_mask`, but \
861                        `rects[{}].array_layers` is not `0..1`",
862                        rect_index
863                    )
864                    .into(),
865                    vuids: &["VUID-vkCmdClearAttachments-baseArrayLayer-00018"],
866                    ..Default::default()
867                }));
868            }
869        }
870
871        Ok(())
872    }
873
874    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
875    pub unsafe fn clear_attachments_unchecked(
876        &mut self,
877        attachments: SmallVec<[ClearAttachment; 4]>,
878        rects: SmallVec<[ClearRect; 4]>,
879    ) -> &mut Self {
880        self.add_command(
881            "clear_attachments",
882            Default::default(),
883            move |out: &mut RecordingCommandBuffer| {
884                unsafe { out.clear_attachments_unchecked(&attachments, &rects) };
885            },
886        );
887
888        self
889    }
890}
891
892impl RecordingCommandBuffer {
893    #[inline]
894    pub unsafe fn begin_render_pass(
895        &mut self,
896        render_pass_begin_info: &RenderPassBeginInfo,
897        subpass_begin_info: &SubpassBeginInfo,
898    ) -> Result<&mut Self, Box<ValidationError>> {
899        self.validate_begin_render_pass(render_pass_begin_info, subpass_begin_info)?;
900
901        Ok(unsafe { self.begin_render_pass_unchecked(render_pass_begin_info, subpass_begin_info) })
902    }
903
904    fn validate_begin_render_pass(
905        &self,
906        render_pass_begin_info: &RenderPassBeginInfo,
907        subpass_begin_info: &SubpassBeginInfo,
908    ) -> Result<(), Box<ValidationError>> {
909        if self.level() != CommandBufferLevel::Primary {
910            return Err(Box::new(ValidationError {
911                problem: "this command buffer is not a primary command buffer".into(),
912                vuids: &["VUID-vkCmdBeginRenderPass2-bufferlevel"],
913                ..Default::default()
914            }));
915        }
916
917        if !self
918            .queue_family_properties()
919            .queue_flags
920            .intersects(QueueFlags::GRAPHICS)
921        {
922            return Err(Box::new(ValidationError {
923                problem: "the queue family of the command buffer does not support \
924                    graphics operations"
925                    .into(),
926                vuids: &["VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool"],
927                ..Default::default()
928            }));
929        }
930
931        render_pass_begin_info
932            .validate(self.device())
933            .map_err(|err| err.add_context("render_pass_begin_info"))?;
934
935        subpass_begin_info
936            .validate(self.device())
937            .map_err(|err| err.add_context("subpass_begin_info"))?;
938
939        let RenderPassBeginInfo {
940            render_pass,
941            framebuffer,
942            render_area_offset: _,
943            render_area_extent: _,
944            clear_values: _,
945            _ne: _,
946        } = render_pass_begin_info;
947
948        for (attachment_index, (attachment_desc, image_view)) in render_pass
949            .attachments()
950            .iter()
951            .zip(framebuffer.attachments())
952            .enumerate()
953        {
954            let attachment_index = attachment_index as u32;
955            let &AttachmentDescription {
956                initial_layout,
957                final_layout,
958                stencil_initial_layout,
959                stencil_final_layout,
960                ..
961            } = attachment_desc;
962
963            for layout in [
964                Some(initial_layout),
965                Some(final_layout),
966                stencil_initial_layout,
967                stencil_final_layout,
968            ]
969            .into_iter()
970            .flatten()
971            {
972                match layout {
973                    ImageLayout::ColorAttachmentOptimal => {
974                        if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
975                            return Err(Box::new(ValidationError {
976                                problem: format!(
977                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
978                                    with the `ImageLayout::ColorAttachmentOptimal` layout, but \
979                                    `framebuffer.attachments()[{0}].usage()` does not contain \
980                                    `ImageUsage::COLOR_ATTACHMENT`",
981                                    attachment_index,
982                                )
983                                .into(),
984                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03094"],
985                                ..Default::default()
986                            }));
987                        }
988                    }
989                    ImageLayout::DepthReadOnlyStencilAttachmentOptimal
990                    | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
991                    | ImageLayout::DepthStencilAttachmentOptimal
992                    | ImageLayout::DepthStencilReadOnlyOptimal
993                    | ImageLayout::DepthAttachmentOptimal
994                    | ImageLayout::DepthReadOnlyOptimal
995                    | ImageLayout::StencilAttachmentOptimal
996                    | ImageLayout::StencilReadOnlyOptimal => {
997                        if !image_view
998                            .usage()
999                            .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1000                        {
1001                            return Err(Box::new(ValidationError {
1002                                problem: format!(
1003                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1004                                    with the \
1005                                    `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`, \
1006                                    `ImageLayout::DepthAttachmentStencilReadOnlyOptimal`, \
1007                                    `ImageLayout::DepthStencilAttachmentOptimal`, \
1008                                    `ImageLayout::DepthStencilReadOnlyOptimal`, \
1009                                    `ImageLayout::DepthAttachmentOptimal`, \
1010                                    `ImageLayout::DepthReadOnlyOptimal`, \
1011                                    `ImageLayout::StencilAttachmentOptimal` or \
1012                                    `ImageLayout::StencilReadOnlyOptimal` layout, but \
1013                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1014                                    `ImageUsage::DEPTH_STENCIL_ATTACHMENT`",
1015                                    attachment_index,
1016                                )
1017                                .into(),
1018                                vuids: &[
1019                                    "VUID-vkCmdBeginRenderPass2-initialLayout-03096",
1020                                    "VUID-vkCmdBeginRenderPass2-initialLayout-02844",
1021                                ],
1022                                ..Default::default()
1023                            }));
1024                        }
1025                    }
1026                    ImageLayout::ShaderReadOnlyOptimal => {
1027                        if !image_view
1028                            .usage()
1029                            .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
1030                        {
1031                            return Err(Box::new(ValidationError {
1032                                problem: format!(
1033                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1034                                    with the `ImageLayout::ShaderReadOnlyOptimal` layout, but \
1035                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1036                                    `ImageUsage::SAMPLED` or `ImageUsage::INPUT_ATTACHMENT`",
1037                                    attachment_index,
1038                                )
1039                                .into(),
1040                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03097"],
1041                                ..Default::default()
1042                            }));
1043                        }
1044                    }
1045                    ImageLayout::TransferSrcOptimal => {
1046                        if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
1047                            return Err(Box::new(ValidationError {
1048                                problem: format!(
1049                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1050                                    with the `ImageLayout::TransferSrcOptimal` layout, but \
1051                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1052                                    `ImageUsage::TRANSFER_SRC`",
1053                                    attachment_index,
1054                                )
1055                                .into(),
1056                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03098"],
1057                                ..Default::default()
1058                            }));
1059                        }
1060                    }
1061                    ImageLayout::TransferDstOptimal => {
1062                        if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
1063                            return Err(Box::new(ValidationError {
1064                                problem: format!(
1065                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1066                                    with the `ImageLayout::TransferDstOptimal` layout, but \
1067                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1068                                    `ImageUsage::TRANSFER_DST`",
1069                                    attachment_index,
1070                                )
1071                                .into(),
1072                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03099"],
1073                                ..Default::default()
1074                            }));
1075                        }
1076                    }
1077                    ImageLayout::Undefined
1078                    | ImageLayout::General
1079                    | ImageLayout::Preinitialized
1080                    | ImageLayout::PresentSrc => (),
1081                }
1082            }
1083        }
1084
1085        for subpass_desc in render_pass.subpasses() {
1086            let SubpassDescription {
1087                flags: _,
1088                view_mask: _,
1089                input_attachments,
1090                color_attachments,
1091                color_resolve_attachments,
1092                depth_stencil_attachment,
1093                depth_stencil_resolve_attachment,
1094                depth_resolve_mode: _,
1095                stencil_resolve_mode: _,
1096                preserve_attachments: _,
1097                _ne: _,
1098            } = subpass_desc;
1099
1100            for atch_ref in input_attachments
1101                .iter()
1102                .flatten()
1103                .chain(color_attachments.iter().flatten())
1104                .chain(color_resolve_attachments.iter().flatten())
1105                .chain(depth_stencil_attachment.iter())
1106                .chain(depth_stencil_resolve_attachment.iter())
1107            {
1108                let image_view = &framebuffer.attachments()[atch_ref.attachment as usize];
1109
1110                match atch_ref.layout {
1111                    ImageLayout::ColorAttachmentOptimal => {
1112                        if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
1113                            return Err(Box::new(ValidationError {
1114                                problem: format!(
1115                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1116                                    with the `ImageLayout::ColorAttachmentOptimal` layout, but \
1117                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1118                                    `ImageUsage::COLOR_ATTACHMENT`",
1119                                    atch_ref.attachment,
1120                                )
1121                                .into(),
1122                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03094"],
1123                                ..Default::default()
1124                            }));
1125                        }
1126                    }
1127                    ImageLayout::DepthReadOnlyStencilAttachmentOptimal
1128                    | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
1129                    | ImageLayout::DepthStencilAttachmentOptimal
1130                    | ImageLayout::DepthStencilReadOnlyOptimal
1131                    | ImageLayout::DepthAttachmentOptimal
1132                    | ImageLayout::DepthReadOnlyOptimal
1133                    | ImageLayout::StencilAttachmentOptimal
1134                    | ImageLayout::StencilReadOnlyOptimal => {
1135                        if !image_view
1136                            .usage()
1137                            .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1138                        {
1139                            return Err(Box::new(ValidationError {
1140                                problem: format!(
1141                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1142                                    with the \
1143                                    `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`, \
1144                                    `ImageLayout::DepthAttachmentStencilReadOnlyOptimal`, \
1145                                    `ImageLayout::DepthStencilAttachmentOptimal`, \
1146                                    `ImageLayout::DepthStencilReadOnlyOptimal`, \
1147                                    `ImageLayout::DepthAttachmentOptimal`, \
1148                                    `ImageLayout::DepthReadOnlyOptimal`, \
1149                                    `ImageLayout::StencilAttachmentOptimal` or \
1150                                    `ImageLayout::StencilReadOnlyOptimal` layout, but \
1151                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1152                                    `ImageUsage::DEPTH_STENCIL_ATTACHMENT`",
1153                                    atch_ref.attachment,
1154                                )
1155                                .into(),
1156                                vuids: &[
1157                                    "VUID-vkCmdBeginRenderPass2-initialLayout-03096",
1158                                    "VUID-vkCmdBeginRenderPass2-initialLayout-02844",
1159                                ],
1160                                ..Default::default()
1161                            }));
1162                        }
1163                    }
1164                    ImageLayout::ShaderReadOnlyOptimal => {
1165                        if !image_view
1166                            .usage()
1167                            .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
1168                        {
1169                            return Err(Box::new(ValidationError {
1170                                problem: format!(
1171                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1172                                    with the `ImageLayout::ShaderReadOnlyOptimal` layout, but \
1173                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1174                                    `ImageUsage::SAMPLED` or `ImageUsage::INPUT_ATTACHMENT`",
1175                                    atch_ref.attachment,
1176                                )
1177                                .into(),
1178                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03097"],
1179                                ..Default::default()
1180                            }));
1181                        }
1182                    }
1183                    ImageLayout::TransferSrcOptimal => {
1184                        if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
1185                            return Err(Box::new(ValidationError {
1186                                problem: format!(
1187                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1188                                    with the `ImageLayout::TransferSrcOptimal` layout, but \
1189                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1190                                    `ImageUsage::TRANSFER_SRC`",
1191                                    atch_ref.attachment,
1192                                )
1193                                .into(),
1194                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03098"],
1195                                ..Default::default()
1196                            }));
1197                        }
1198                    }
1199                    ImageLayout::TransferDstOptimal => {
1200                        if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
1201                            return Err(Box::new(ValidationError {
1202                                problem: format!(
1203                                    "`framebuffer.attachments()[{0}]` is used in `render_pass` \
1204                                    with the `ImageLayout::TransferDstOptimal` layout, but \
1205                                    `framebuffer.attachments()[{0}].usage()` does not contain \
1206                                    `ImageUsage::TRANSFER_DST`",
1207                                    atch_ref.attachment,
1208                                )
1209                                .into(),
1210                                vuids: &["VUID-vkCmdBeginRenderPass2-initialLayout-03099"],
1211                                ..Default::default()
1212                            }));
1213                        }
1214                    }
1215                    ImageLayout::Undefined
1216                    | ImageLayout::General
1217                    | ImageLayout::Preinitialized
1218                    | ImageLayout::PresentSrc => (),
1219                }
1220            }
1221        }
1222
1223        // VUID-vkCmdBeginRenderPass2-initialLayout-03100
1224        // TODO:
1225
1226        // VUID-vkCmdBeginRenderPass2-srcStageMask-06453
1227        // TODO:
1228
1229        // VUID-vkCmdBeginRenderPass2-dstStageMask-06454
1230        // TODO:
1231
1232        // VUID-vkCmdBeginRenderPass2-framebuffer-02533
1233        // For any attachment in framebuffer that is used by renderPass and is bound to memory
1234        // locations that are also bound to another attachment used by renderPass, and if at least
1235        // one of those uses causes either attachment to be written to, both attachments
1236        // must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set
1237
1238        Ok(())
1239    }
1240
1241    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1242    pub unsafe fn begin_render_pass_unchecked(
1243        &mut self,
1244        render_pass_begin_info: &RenderPassBeginInfo,
1245        subpass_begin_info: &SubpassBeginInfo,
1246    ) -> &mut Self {
1247        let render_pass_begin_info_fields1_vk = render_pass_begin_info.to_vk_fields1();
1248        let render_pass_begin_info_vk =
1249            render_pass_begin_info.to_vk(&render_pass_begin_info_fields1_vk);
1250
1251        let subpass_begin_info_vk = subpass_begin_info.to_vk();
1252
1253        let fns = self.device().fns();
1254
1255        if self.device().api_version() >= Version::V1_2
1256            || self.device().enabled_extensions().khr_create_renderpass2
1257        {
1258            if self.device().api_version() >= Version::V1_2 {
1259                unsafe {
1260                    (fns.v1_2.cmd_begin_render_pass2)(
1261                        self.handle(),
1262                        &render_pass_begin_info_vk,
1263                        &subpass_begin_info_vk,
1264                    )
1265                };
1266            } else {
1267                unsafe {
1268                    (fns.khr_create_renderpass2.cmd_begin_render_pass2_khr)(
1269                        self.handle(),
1270                        &render_pass_begin_info_vk,
1271                        &subpass_begin_info_vk,
1272                    )
1273                };
1274            }
1275        } else {
1276            debug_assert!(subpass_begin_info_vk.p_next.is_null());
1277
1278            unsafe {
1279                (fns.v1_0.cmd_begin_render_pass)(
1280                    self.handle(),
1281                    &render_pass_begin_info_vk,
1282                    subpass_begin_info_vk.contents,
1283                )
1284            };
1285        }
1286
1287        self
1288    }
1289
1290    #[inline]
1291    pub unsafe fn next_subpass(
1292        &mut self,
1293        subpass_end_info: &SubpassEndInfo,
1294        subpass_begin_info: &SubpassBeginInfo,
1295    ) -> Result<&mut Self, Box<ValidationError>> {
1296        self.validate_next_subpass(subpass_end_info, subpass_begin_info)?;
1297
1298        Ok(unsafe { self.next_subpass_unchecked(subpass_end_info, subpass_begin_info) })
1299    }
1300
1301    fn validate_next_subpass(
1302        &self,
1303        subpass_end_info: &SubpassEndInfo,
1304        subpass_begin_info: &SubpassBeginInfo,
1305    ) -> Result<(), Box<ValidationError>> {
1306        if self.level() != CommandBufferLevel::Primary {
1307            return Err(Box::new(ValidationError {
1308                problem: "this command buffer is not a primary command buffer".into(),
1309                vuids: &["VUID-vkCmdNextSubpass2-bufferlevel"],
1310                ..Default::default()
1311            }));
1312        }
1313
1314        if !self
1315            .queue_family_properties()
1316            .queue_flags
1317            .intersects(QueueFlags::GRAPHICS)
1318        {
1319            return Err(Box::new(ValidationError {
1320                problem: "the queue family of the command buffer does not support \
1321                    graphics operations"
1322                    .into(),
1323                vuids: &["VUID-vkCmdNextSubpass2-commandBuffer-cmdpool"],
1324                ..Default::default()
1325            }));
1326        }
1327
1328        subpass_end_info
1329            .validate(self.device())
1330            .map_err(|err| err.add_context("subpass_end_info"))?;
1331
1332        subpass_begin_info
1333            .validate(self.device())
1334            .map_err(|err| err.add_context("subpass_begin_info"))?;
1335
1336        Ok(())
1337    }
1338
1339    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1340    pub unsafe fn next_subpass_unchecked(
1341        &mut self,
1342        subpass_end_info: &SubpassEndInfo,
1343        subpass_begin_info: &SubpassBeginInfo,
1344    ) -> &mut Self {
1345        let fns = self.device().fns();
1346
1347        let subpass_end_info_vk = subpass_end_info.to_vk();
1348        let subpass_begin_info_vk = subpass_begin_info.to_vk();
1349
1350        if self.device().api_version() >= Version::V1_2
1351            || self.device().enabled_extensions().khr_create_renderpass2
1352        {
1353            if self.device().api_version() >= Version::V1_2 {
1354                unsafe {
1355                    (fns.v1_2.cmd_next_subpass2)(
1356                        self.handle(),
1357                        &subpass_begin_info_vk,
1358                        &subpass_end_info_vk,
1359                    )
1360                };
1361            } else {
1362                unsafe {
1363                    (fns.khr_create_renderpass2.cmd_next_subpass2_khr)(
1364                        self.handle(),
1365                        &subpass_begin_info_vk,
1366                        &subpass_end_info_vk,
1367                    )
1368                };
1369            }
1370        } else {
1371            debug_assert!(subpass_begin_info_vk.p_next.is_null());
1372            debug_assert!(subpass_end_info_vk.p_next.is_null());
1373
1374            unsafe { (fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info_vk.contents) };
1375        }
1376
1377        self
1378    }
1379
1380    #[inline]
1381    pub unsafe fn end_render_pass(
1382        &mut self,
1383        subpass_end_info: &SubpassEndInfo,
1384    ) -> Result<&mut Self, Box<ValidationError>> {
1385        self.validate_end_render_pass(subpass_end_info)?;
1386
1387        Ok(unsafe { self.end_render_pass_unchecked(subpass_end_info) })
1388    }
1389
1390    fn validate_end_render_pass(
1391        &self,
1392        subpass_end_info: &SubpassEndInfo,
1393    ) -> Result<(), Box<ValidationError>> {
1394        if self.level() != CommandBufferLevel::Primary {
1395            return Err(Box::new(ValidationError {
1396                problem: "this command buffer is not a primary command buffer".into(),
1397                vuids: &["VUID-vkCmdEndRenderPass2-bufferlevel"],
1398                ..Default::default()
1399            }));
1400        }
1401
1402        if !self
1403            .queue_family_properties()
1404            .queue_flags
1405            .intersects(QueueFlags::GRAPHICS)
1406        {
1407            return Err(Box::new(ValidationError {
1408                problem: "the queue family of the command buffer does not support \
1409                    graphics operations"
1410                    .into(),
1411                vuids: &["VUID-vkCmdEndRenderPass2-commandBuffer-cmdpool"],
1412                ..Default::default()
1413            }));
1414        }
1415
1416        subpass_end_info
1417            .validate(self.device())
1418            .map_err(|err| err.add_context("subpass_end_info"))?;
1419
1420        Ok(())
1421    }
1422
1423    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1424    pub unsafe fn end_render_pass_unchecked(
1425        &mut self,
1426        subpass_end_info: &SubpassEndInfo,
1427    ) -> &mut Self {
1428        let subpass_end_info_vk = subpass_end_info.to_vk();
1429
1430        let fns = self.device().fns();
1431
1432        if self.device().api_version() >= Version::V1_2
1433            || self.device().enabled_extensions().khr_create_renderpass2
1434        {
1435            if self.device().api_version() >= Version::V1_2 {
1436                unsafe { (fns.v1_2.cmd_end_render_pass2)(self.handle(), &subpass_end_info_vk) };
1437            } else {
1438                unsafe {
1439                    (fns.khr_create_renderpass2.cmd_end_render_pass2_khr)(
1440                        self.handle(),
1441                        &subpass_end_info_vk,
1442                    )
1443                };
1444            }
1445        } else {
1446            debug_assert!(subpass_end_info_vk.p_next.is_null());
1447
1448            unsafe { (fns.v1_0.cmd_end_render_pass)(self.handle()) };
1449        }
1450
1451        self
1452    }
1453
1454    #[inline]
1455    pub unsafe fn begin_rendering(
1456        &mut self,
1457        rendering_info: &RenderingInfo,
1458    ) -> Result<&mut Self, Box<ValidationError>> {
1459        self.validate_begin_rendering(rendering_info)?;
1460
1461        Ok(unsafe { self.begin_rendering_unchecked(rendering_info) })
1462    }
1463
1464    fn validate_begin_rendering(
1465        &self,
1466        rendering_info: &RenderingInfo,
1467    ) -> Result<(), Box<ValidationError>> {
1468        let device = self.device();
1469
1470        if !device.enabled_features().dynamic_rendering {
1471            return Err(Box::new(ValidationError {
1472                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1473                    "dynamic_rendering",
1474                )])]),
1475                vuids: &["VUID-vkCmdBeginRendering-dynamicRendering-06446"],
1476                ..Default::default()
1477            }));
1478        }
1479
1480        if !self
1481            .queue_family_properties()
1482            .queue_flags
1483            .intersects(QueueFlags::GRAPHICS)
1484        {
1485            return Err(Box::new(ValidationError {
1486                problem: "the queue family of the command buffer does not support \
1487                    graphics operations"
1488                    .into(),
1489                vuids: &["VUID-vkCmdBeginRendering-commandBuffer-cmdpool"],
1490                ..Default::default()
1491            }));
1492        }
1493
1494        rendering_info
1495            .validate(self.device())
1496            .map_err(|err| err.add_context("rendering_info"))?;
1497
1498        let &RenderingInfo {
1499            render_area_offset: _,
1500            render_area_extent: _,
1501            layer_count: _,
1502            view_mask: _,
1503            color_attachments: _,
1504            depth_attachment: _,
1505            stencil_attachment: _,
1506            contents,
1507            _ne: _,
1508        } = rendering_info;
1509
1510        if self.level() == CommandBufferLevel::Secondary
1511            && contents == SubpassContents::SecondaryCommandBuffers
1512        {
1513            return Err(Box::new(ValidationError {
1514                problem: "this command buffer is a secondary command buffer, but \
1515                    `rendering_info.contents` is `SubpassContents::SecondaryCommandBuffers`"
1516                    .into(),
1517                vuids: &["VUID-vkCmdBeginRendering-commandBuffer-06068"],
1518                ..Default::default()
1519            }));
1520        }
1521
1522        Ok(())
1523    }
1524
1525    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1526    pub unsafe fn begin_rendering_unchecked(
1527        &mut self,
1528        rendering_info: &RenderingInfo,
1529    ) -> &mut Self {
1530        let rendering_info_fields1_vk = rendering_info.to_vk_fields1();
1531        let rendering_info_vk = rendering_info.to_vk(&rendering_info_fields1_vk);
1532
1533        let fns = self.device().fns();
1534
1535        if self.device().api_version() >= Version::V1_3 {
1536            unsafe { (fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info_vk) };
1537        } else {
1538            unsafe {
1539                (fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(
1540                    self.handle(),
1541                    &rendering_info_vk,
1542                )
1543            };
1544        }
1545
1546        self
1547    }
1548
1549    #[inline]
1550    pub unsafe fn end_rendering(&mut self) -> Result<&mut Self, Box<ValidationError>> {
1551        self.validate_end_rendering()?;
1552
1553        Ok(unsafe { self.end_rendering_unchecked() })
1554    }
1555
1556    fn validate_end_rendering(&self) -> Result<(), Box<ValidationError>> {
1557        if !self
1558            .queue_family_properties()
1559            .queue_flags
1560            .intersects(QueueFlags::GRAPHICS)
1561        {
1562            return Err(Box::new(ValidationError {
1563                problem: "the queue family of the command buffer does not support \
1564                    graphics operations"
1565                    .into(),
1566                vuids: &["VUID-vkCmdEndRendering-commandBuffer-cmdpool"],
1567                ..Default::default()
1568            }));
1569        }
1570
1571        Ok(())
1572    }
1573
1574    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1575    pub unsafe fn end_rendering_unchecked(&mut self) -> &mut Self {
1576        let fns = self.device().fns();
1577
1578        if self.device().api_version() >= Version::V1_3 {
1579            unsafe { (fns.v1_3.cmd_end_rendering)(self.handle()) };
1580        } else {
1581            unsafe { (fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle()) };
1582        }
1583
1584        self
1585    }
1586
1587    #[inline]
1588    pub unsafe fn clear_attachments(
1589        &mut self,
1590        attachments: &[ClearAttachment],
1591        rects: &[ClearRect],
1592    ) -> Result<&mut Self, Box<ValidationError>> {
1593        self.validate_clear_attachments(attachments, rects)?;
1594
1595        Ok(unsafe { self.clear_attachments_unchecked(attachments, rects) })
1596    }
1597
1598    fn validate_clear_attachments(
1599        &self,
1600        attachments: &[ClearAttachment],
1601        rects: &[ClearRect],
1602    ) -> Result<(), Box<ValidationError>> {
1603        if !self
1604            .queue_family_properties()
1605            .queue_flags
1606            .intersects(QueueFlags::GRAPHICS)
1607        {
1608            return Err(Box::new(ValidationError {
1609                problem: "the queue family of the command buffer does not support \
1610                    graphics operations"
1611                    .into(),
1612                vuids: &["VUID-vkCmdClearAttachments-commandBuffer-cmdpool"],
1613                ..Default::default()
1614            }));
1615        }
1616
1617        for (clear_index, clear_attachment) in attachments.iter().enumerate() {
1618            clear_attachment
1619                .validate(self.device())
1620                .map_err(|err| err.add_context(format!("attachments[{}]", clear_index)))?;
1621        }
1622
1623        for (rect_index, rect) in rects.iter().enumerate() {
1624            let &ClearRect {
1625                offset: _,
1626                extent,
1627                ref array_layers,
1628            } = rect;
1629
1630            if extent[0] == 0 {
1631                return Err(Box::new(ValidationError {
1632                    context: format!("rects[{}].extent[0]", rect_index).into(),
1633                    problem: "is 0".into(),
1634                    vuids: &["VUID-vkCmdClearAttachments-rect-02682"],
1635                    ..Default::default()
1636                }));
1637            }
1638
1639            if extent[1] == 0 {
1640                return Err(Box::new(ValidationError {
1641                    context: format!("rects[{}].extent[1]", rect_index).into(),
1642                    problem: "is 0".into(),
1643                    vuids: &["VUID-vkCmdClearAttachments-rect-02683"],
1644                    ..Default::default()
1645                }));
1646            }
1647
1648            if array_layers.is_empty() {
1649                return Err(Box::new(ValidationError {
1650                    context: format!("rects[{}].array_layers", rect_index).into(),
1651                    problem: "is empty".into(),
1652                    vuids: &["VUID-vkCmdClearAttachments-layerCount-01934"],
1653                    ..Default::default()
1654                }));
1655            }
1656        }
1657
1658        Ok(())
1659    }
1660
1661    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1662    pub unsafe fn clear_attachments_unchecked(
1663        &mut self,
1664        attachments: &[ClearAttachment],
1665        rects: &[ClearRect],
1666    ) -> &mut Self {
1667        if attachments.is_empty() || rects.is_empty() {
1668            return self;
1669        }
1670
1671        let attachments_vk: SmallVec<[_; 4]> =
1672            attachments.iter().map(ClearAttachment::to_vk).collect();
1673        let rects_vk: SmallVec<[_; 4]> = rects.iter().map(ClearRect::to_vk).collect();
1674
1675        let fns = self.device().fns();
1676        unsafe {
1677            (fns.v1_0.cmd_clear_attachments)(
1678                self.handle(),
1679                attachments_vk.len() as u32,
1680                attachments_vk.as_ptr(),
1681                rects_vk.len() as u32,
1682                rects_vk.as_ptr(),
1683            )
1684        };
1685
1686        self
1687    }
1688}
1689
1690/// Parameters to begin a new render pass.
1691#[derive(Clone, Debug)]
1692pub struct RenderPassBeginInfo {
1693    /// The render pass to begin.
1694    ///
1695    /// If this is not the render pass that `framebuffer` was created with, it must be compatible
1696    /// with that render pass.
1697    ///
1698    /// The default value is the render pass of `framebuffer`.
1699    pub render_pass: Arc<RenderPass>,
1700
1701    /// The framebuffer to use for rendering.
1702    ///
1703    /// There is no default value.
1704    pub framebuffer: Arc<Framebuffer>,
1705
1706    /// The offset from the top left corner of the framebuffer that will be rendered to.
1707    ///
1708    /// The default value is `[0, 0]`.
1709    pub render_area_offset: [u32; 2],
1710
1711    /// The size of the area that will be rendered to.
1712    ///
1713    /// `render_area_offset + render_area_extent` must not be greater than
1714    /// [`framebuffer.extent()`].
1715    ///
1716    /// The default value is [`framebuffer.extent()`].
1717    pub render_area_extent: [u32; 2],
1718
1719    /// Provides, for each attachment in `render_pass` that has a load operation of
1720    /// [`AttachmentLoadOp::Clear`], the clear values that should be used for the attachments in
1721    /// the framebuffer.
1722    /// There must be exactly [`framebuffer.attachments().len()`] elements provided,
1723    /// and each one must match the attachment format.
1724    ///
1725    /// To skip over an attachment whose load operation is something else, provide `None`.
1726    ///
1727    /// The default value is empty, which must be overridden if the framebuffer has attachments.
1728    pub clear_values: Vec<Option<ClearValue>>,
1729
1730    pub _ne: crate::NonExhaustive,
1731}
1732
1733impl RenderPassBeginInfo {
1734    #[inline]
1735    pub fn framebuffer(framebuffer: Arc<Framebuffer>) -> Self {
1736        let render_area_extent = framebuffer.extent();
1737
1738        Self {
1739            render_pass: framebuffer.render_pass().clone(),
1740            framebuffer,
1741            render_area_offset: [0, 0],
1742            render_area_extent,
1743            clear_values: Vec::new(),
1744            _ne: crate::NonExhaustive(()),
1745        }
1746    }
1747
1748    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1749        let &Self {
1750            ref render_pass,
1751            ref framebuffer,
1752            render_area_offset,
1753            render_area_extent,
1754            ref clear_values,
1755            _ne,
1756        } = self;
1757
1758        // VUID-VkRenderPassBeginInfo-commonparent
1759        // VUID-vkCmdBeginRenderPass2-framebuffer-02779
1760        assert_eq!(device, framebuffer.device().as_ref());
1761
1762        if !render_pass.is_compatible_with(framebuffer.render_pass()) {
1763            return Err(Box::new(ValidationError {
1764                problem: "`render_pass` is not compatible with `framebuffer.render_pass()`".into(),
1765                vuids: &["VUID-VkRenderPassBeginInfo-renderPass-00904"],
1766                ..Default::default()
1767            }));
1768        }
1769
1770        if render_area_extent[0] == 0 {
1771            return Err(Box::new(ValidationError {
1772                context: "render_area_extent[0]".into(),
1773                problem: "is 0".into(),
1774                vuids: &["VUID-VkRenderPassBeginInfo-None-08996"],
1775                ..Default::default()
1776            }));
1777        }
1778
1779        if render_area_extent[1] == 0 {
1780            return Err(Box::new(ValidationError {
1781                context: "render_area_extent[1]".into(),
1782                problem: "is 0".into(),
1783                vuids: &["VUID-VkRenderPassBeginInfo-None-08997"],
1784                ..Default::default()
1785            }));
1786        }
1787
1788        if render_area_offset[0] + render_area_extent[0] > framebuffer.extent()[0] {
1789            return Err(Box::new(ValidationError {
1790                problem: "`render_area_offset[0] + render_area_extent[0]` is greater than \
1791                    `framebuffer.extent()[0]`"
1792                    .into(),
1793                vuids: &["VUID-VkRenderPassBeginInfo-pNext-02852"],
1794                ..Default::default()
1795            }));
1796        }
1797
1798        if render_area_offset[1] + render_area_extent[1] > framebuffer.extent()[1] {
1799            return Err(Box::new(ValidationError {
1800                problem: "`render_area_offset[1] + render_area_extent[1]` is greater than \
1801                    `framebuffer.extent()[1]`"
1802                    .into(),
1803                vuids: &["VUID-VkRenderPassBeginInfo-pNext-02853"],
1804                ..Default::default()
1805            }));
1806        }
1807
1808        if clear_values.len() != render_pass.attachments().len() {
1809            return Err(Box::new(ValidationError {
1810                problem: "`clear_values.len()` is not equal to `render_pass.attachments().len()`"
1811                    .into(),
1812                vuids: &["VUID-VkRenderPassBeginInfo-clearValueCount-00902"],
1813                ..Default::default()
1814            }));
1815        }
1816
1817        // VUID-VkRenderPassBeginInfo-clearValueCount-04962
1818        for (attachment_index, (attachment_desc, clear_value)) in render_pass
1819            .attachments()
1820            .iter()
1821            .zip(clear_values)
1822            .enumerate()
1823        {
1824            match (clear_value, attachment_desc.required_clear_value()) {
1825                (None, None) => continue,
1826                (None, Some(_)) => {
1827                    return Err(Box::new(ValidationError {
1828                        problem: format!(
1829                            "`render_pass.attachments()[{0}]` requires a clear value, but \
1830                            `clear_values[{0}]` is `None`",
1831                            attachment_index
1832                        )
1833                        .into(),
1834                        ..Default::default()
1835                    }));
1836                }
1837                (Some(_), None) => {
1838                    return Err(Box::new(ValidationError {
1839                        problem: format!(
1840                            "`render_pass.attachments()[{0}]` does not require a clear value, but \
1841                            `clear_values[{0}]` is `Some`",
1842                            attachment_index
1843                        )
1844                        .into(),
1845                        ..Default::default()
1846                    }));
1847                }
1848                (Some(clear_value), Some(required_clear_value)) => {
1849                    if required_clear_value != clear_value.clear_value_type() {
1850                        return Err(Box::new(ValidationError {
1851                            problem: format!(
1852                                "`clear_values[{0}]` is `ClearValue::{1:?}`, but \
1853                                `render_pass.attachments()[{0}]` requires a clear value of type \
1854                                `ClearValue::{2:?}`",
1855                                attachment_index,
1856                                clear_value.clear_value_type(),
1857                                required_clear_value,
1858                            )
1859                            .into(),
1860                            ..Default::default()
1861                        }));
1862                    }
1863
1864                    clear_value.validate(device).map_err(|err| {
1865                        err.add_context(format!("clear_values[{}]", attachment_index))
1866                    })?;
1867                }
1868            }
1869        }
1870
1871        Ok(())
1872    }
1873
1874    pub(crate) fn to_vk<'a>(
1875        &self,
1876        fields1_vk: &'a RenderPassBeginInfoFields1Vk,
1877    ) -> ash::vk::RenderPassBeginInfo<'a> {
1878        let &Self {
1879            ref render_pass,
1880            ref framebuffer,
1881            render_area_offset,
1882            render_area_extent,
1883            clear_values: _,
1884            _ne,
1885        } = self;
1886        let RenderPassBeginInfoFields1Vk { clear_values_vk } = fields1_vk;
1887
1888        ash::vk::RenderPassBeginInfo::default()
1889            .render_pass(render_pass.handle())
1890            .framebuffer(framebuffer.handle())
1891            .render_area(ash::vk::Rect2D {
1892                offset: ash::vk::Offset2D {
1893                    x: render_area_offset[0] as i32,
1894                    y: render_area_offset[1] as i32,
1895                },
1896                extent: ash::vk::Extent2D {
1897                    width: render_area_extent[0],
1898                    height: render_area_extent[1],
1899                },
1900            })
1901            .clear_values(clear_values_vk)
1902    }
1903
1904    pub(crate) fn to_vk_fields1(&self) -> RenderPassBeginInfoFields1Vk {
1905        let clear_values_vk = self
1906            .clear_values
1907            .iter()
1908            .map(|clear_value| {
1909                clear_value
1910                    .as_ref()
1911                    .map_or_else(Default::default, ClearValue::to_vk)
1912            })
1913            .collect();
1914
1915        RenderPassBeginInfoFields1Vk { clear_values_vk }
1916    }
1917}
1918
1919pub(crate) struct RenderPassBeginInfoFields1Vk {
1920    pub(crate) clear_values_vk: SmallVec<[ash::vk::ClearValue; 4]>,
1921}
1922
1923/// Parameters to begin a new subpass within a render pass.
1924#[derive(Clone, Debug)]
1925pub struct SubpassBeginInfo {
1926    /// What kinds of commands will be recorded in the subpass.
1927    ///
1928    /// The default value is [`SubpassContents::Inline`].
1929    pub contents: SubpassContents,
1930
1931    pub _ne: crate::NonExhaustive,
1932}
1933
1934impl Default for SubpassBeginInfo {
1935    #[inline]
1936    fn default() -> Self {
1937        Self {
1938            contents: SubpassContents::Inline,
1939            _ne: crate::NonExhaustive(()),
1940        }
1941    }
1942}
1943
1944impl SubpassBeginInfo {
1945    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1946        let &Self { contents, _ne: _ } = self;
1947
1948        contents.validate_device(device).map_err(|err| {
1949            err.add_context("contents")
1950                .set_vuids(&["VUID-VkSubpassBeginInfo-contents-parameter"])
1951        })?;
1952
1953        Ok(())
1954    }
1955
1956    pub(crate) fn to_vk(&self) -> ash::vk::SubpassBeginInfo<'static> {
1957        let &Self { contents, _ne: _ } = self;
1958
1959        ash::vk::SubpassBeginInfo::default().contents(contents.into())
1960    }
1961}
1962
1963/// Parameters to end the current subpass within a render pass.
1964#[derive(Clone, Debug)]
1965pub struct SubpassEndInfo {
1966    pub _ne: crate::NonExhaustive,
1967}
1968
1969impl Default for SubpassEndInfo {
1970    #[inline]
1971    fn default() -> Self {
1972        Self {
1973            _ne: crate::NonExhaustive(()),
1974        }
1975    }
1976}
1977
1978impl SubpassEndInfo {
1979    pub(crate) fn validate(&self, _device: &Device) -> Result<(), Box<ValidationError>> {
1980        let &Self { _ne: _ } = self;
1981
1982        Ok(())
1983    }
1984
1985    pub(crate) fn to_vk(&self) -> ash::vk::SubpassEndInfo<'static> {
1986        let &Self { _ne: _ } = self;
1987
1988        ash::vk::SubpassEndInfo::default()
1989    }
1990}
1991
1992/// Parameters to begin rendering.
1993#[derive(Clone, Debug)]
1994pub struct RenderingInfo {
1995    /// The offset from the top left corner of the attachments that will be rendered to.
1996    ///
1997    /// This value must be smaller than the smallest width and height of the attachment images.
1998    ///
1999    /// The default value is `[0, 0]`.
2000    pub render_area_offset: [u32; 2],
2001
2002    /// The size of the area that will be rendered to.
2003    ///
2004    /// This value plus `render_area_offset` must be no larger than the smallest width and height
2005    /// of the attachment images.
2006    /// If one of the elements is set to 0, the extent will be calculated automatically from the
2007    /// extents of the attachment images to be the largest allowed. At least one attachment image
2008    /// must be specified in that case.
2009    ///
2010    /// The default value is `[0, 0]`.
2011    pub render_area_extent: [u32; 2],
2012
2013    /// The number of layers of the attachments that will be rendered to.
2014    ///
2015    /// This must be no larger than the smallest number of array layers of the attachment images.
2016    /// If set to 0, the number of layers will be calculated automatically from the
2017    /// layer ranges of the attachment images to be the largest allowed. At least one attachment
2018    /// image must be specified in that case.
2019    ///
2020    /// If the render pass uses multiview (`view_mask` is not 0), then this value must be 0 or 1.
2021    ///
2022    /// The default value is `0`.
2023    pub layer_count: u32,
2024
2025    /// If not `0`, enables multiview rendering, and specifies the view indices that are rendered
2026    /// to. The value is a bitmask, so that that for example `0b11` will draw to the first two
2027    /// views and `0b101` will draw to the first and third view.
2028    ///
2029    /// If set to a nonzero value, the [`multiview`](crate::device::DeviceFeatures::multiview)
2030    /// feature must be enabled on the device.
2031    ///
2032    /// The default value is `0`.
2033    pub view_mask: u32,
2034
2035    /// The color attachments to use for rendering.
2036    ///
2037    /// The number of color attachments must be less than the
2038    /// [`max_color_attachments`](crate::device::DeviceProperties::max_color_attachments) limit of
2039    /// the physical device. All color attachments must have the same `samples` value.
2040    ///
2041    /// The default value is empty.
2042    pub color_attachments: Vec<Option<RenderingAttachmentInfo>>,
2043
2044    /// The depth attachment to use for rendering.
2045    ///
2046    /// If set to `Some`, the image view must have the same `samples` value as those in
2047    /// `color_attachments`.
2048    ///
2049    /// The default value is `None`.
2050    pub depth_attachment: Option<RenderingAttachmentInfo>,
2051
2052    /// The stencil attachment to use for rendering.
2053    ///
2054    /// If set to `Some`, the image view must have the same `samples` value as those in
2055    /// `color_attachments`.
2056    ///
2057    /// The default value is `None`.
2058    pub stencil_attachment: Option<RenderingAttachmentInfo>,
2059
2060    /// What kinds of commands will be recorded in the render pass: either inline draw commands, or
2061    /// executions of secondary command buffers.
2062    ///
2063    /// If recorded in a secondary command buffer, this must be [`SubpassContents::Inline`].
2064    ///
2065    /// The default value is [`SubpassContents::Inline`].
2066    pub contents: SubpassContents,
2067
2068    pub _ne: crate::NonExhaustive,
2069}
2070
2071impl Default for RenderingInfo {
2072    #[inline]
2073    fn default() -> Self {
2074        Self {
2075            render_area_offset: [0, 0],
2076            render_area_extent: [0, 0],
2077            layer_count: 0,
2078            view_mask: 0,
2079            color_attachments: Vec::new(),
2080            depth_attachment: None,
2081            stencil_attachment: None,
2082            contents: SubpassContents::Inline,
2083            _ne: crate::NonExhaustive(()),
2084        }
2085    }
2086}
2087
2088impl RenderingInfo {
2089    pub(crate) fn set_auto_extent_layers(&mut self) {
2090        let &mut RenderingInfo {
2091            render_area_offset,
2092            ref mut render_area_extent,
2093            ref mut layer_count,
2094            view_mask,
2095            ref color_attachments,
2096            ref depth_attachment,
2097            ref stencil_attachment,
2098            contents: _,
2099            _ne: _,
2100        } = self;
2101
2102        let is_auto_extent = render_area_extent[0] == 0 || render_area_extent[1] == 0;
2103        let is_auto_layers = *layer_count == 0;
2104
2105        if (is_auto_extent || is_auto_layers)
2106            && !(color_attachments.is_empty()
2107                && depth_attachment.is_none()
2108                && stencil_attachment.is_none())
2109        {
2110            let mut auto_extent = [u32::MAX, u32::MAX];
2111            let mut auto_layers = if view_mask != 0 { 1 } else { u32::MAX };
2112
2113            if is_auto_extent {
2114                *render_area_extent = [u32::MAX, u32::MAX];
2115            }
2116
2117            if is_auto_layers {
2118                if view_mask != 0 {
2119                    *layer_count = 1;
2120                } else {
2121                    *layer_count = u32::MAX;
2122                }
2123            }
2124
2125            for image_view in color_attachments
2126                .iter()
2127                .flatten()
2128                .chain(depth_attachment.iter())
2129                .chain(stencil_attachment.iter())
2130                .flat_map(|attachment_info| {
2131                    Some(&attachment_info.image_view).into_iter().chain(
2132                        attachment_info
2133                            .resolve_info
2134                            .as_ref()
2135                            .map(|resolve_info| &resolve_info.image_view),
2136                    )
2137                })
2138            {
2139                let image_view_extent = image_view.image().extent();
2140                let image_view_array_layers =
2141                    image_view.subresource_range().array_layers.len() as u32;
2142
2143                auto_extent[0] = auto_extent[0].min(image_view_extent[0]);
2144                auto_extent[1] = auto_extent[1].min(image_view_extent[1]);
2145                auto_layers = auto_layers.min(image_view_array_layers);
2146            }
2147
2148            if is_auto_extent {
2149                // Subtract the offset from the calculated max extent.
2150                // If there is an underflow, then the offset is too large, and validation should
2151                // catch that later.
2152                for i in 0..2 {
2153                    render_area_extent[i] = auto_extent[i]
2154                        .checked_sub(render_area_offset[i])
2155                        .unwrap_or(1);
2156                }
2157            }
2158
2159            if is_auto_layers {
2160                *layer_count = auto_layers;
2161            }
2162        }
2163    }
2164
2165    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
2166        let &Self {
2167            render_area_offset,
2168            render_area_extent,
2169            layer_count,
2170            view_mask,
2171            ref color_attachments,
2172            ref depth_attachment,
2173            ref stencil_attachment,
2174            contents,
2175            _ne: _,
2176        } = self;
2177
2178        let properties = device.physical_device().properties();
2179
2180        contents.validate_device(device).map_err(|err| {
2181            err.add_context("contents")
2182                .set_vuids(&["VUID-VkRenderingInfo-flags-parameter"])
2183        })?;
2184
2185        if render_area_extent[0] == 0 {
2186            return Err(Box::new(ValidationError {
2187                context: "render_area_extent[0]".into(),
2188                problem: "is 0".into(),
2189                vuids: &["VUID-VkRenderingInfo-None-08994"],
2190                ..Default::default()
2191            }));
2192        }
2193
2194        if render_area_extent[1] == 0 {
2195            return Err(Box::new(ValidationError {
2196                context: "render_area_extent[1]".into(),
2197                problem: "is 0".into(),
2198                vuids: &["VUID-VkRenderingInfo-None-08995"],
2199                ..Default::default()
2200            }));
2201        }
2202
2203        if render_area_offset[0] + render_area_extent[0] > properties.max_framebuffer_width {
2204            return Err(Box::new(ValidationError {
2205                problem: "`render_area_offset[0] + render_area_extent[0]` is greater than the \
2206                    `max_framebuffer_width` limit"
2207                    .into(),
2208                vuids: &["VUID-VkRenderingInfo-pNext-07815"],
2209                ..Default::default()
2210            }));
2211        }
2212
2213        if render_area_offset[1] + render_area_extent[1] > properties.max_framebuffer_height {
2214            return Err(Box::new(ValidationError {
2215                problem: "`render_area_offset[1] + render_area_extent[1]` is greater than the \
2216                    `max_framebuffer_height` limit"
2217                    .into(),
2218                vuids: &["VUID-VkRenderingInfo-pNext-07816"],
2219                ..Default::default()
2220            }));
2221        }
2222
2223        // No VUID, but for sanity it makes sense to treat this the same as in framebuffers.
2224        if view_mask != 0 && layer_count != 1 {
2225            return Err(Box::new(ValidationError {
2226                problem: "`view_mask` is not 0, but `layer_count` is not 1".into(),
2227                // vuids?
2228                ..Default::default()
2229            }));
2230        }
2231
2232        if view_mask != 0 && !device.enabled_features().multiview {
2233            return Err(Box::new(ValidationError {
2234                context: "view_mask".into(),
2235                problem: "is not 0".into(),
2236                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2237                    "multiview",
2238                )])]),
2239                vuids: &["VUID-VkRenderingInfo-multiview-06127"],
2240            }));
2241        }
2242
2243        let highest_view_index = u32::BITS - view_mask.leading_zeros();
2244
2245        if highest_view_index > properties.max_multiview_view_count.unwrap_or(0) {
2246            return Err(Box::new(ValidationError {
2247                context: "view_mask".into(),
2248                problem: "the highest enabled view index is not less than the \
2249                    `max_multiview_view_count` limit"
2250                    .into(),
2251                vuids: &["VUID-VkRenderingInfo-viewMask-06128"],
2252                ..Default::default()
2253            }));
2254        }
2255
2256        let mut samples = None;
2257
2258        if color_attachments.len() > properties.max_color_attachments as usize {
2259            return Err(Box::new(ValidationError {
2260                context: "color_attachments".into(),
2261                problem: "the number of elements is greater than the `max_color_attachments` limit"
2262                    .into(),
2263                vuids: &["VUID-VkRenderingInfo-colorAttachmentCount-06106"],
2264                ..Default::default()
2265            }));
2266        }
2267
2268        for (attachment_index, attachment_info) in
2269            color_attachments
2270                .iter()
2271                .enumerate()
2272                .filter_map(|(index, attachment_info)| {
2273                    attachment_info
2274                        .as_ref()
2275                        .map(|attachment_info| (index, attachment_info))
2276                })
2277        {
2278            attachment_info.validate(device).map_err(|err| {
2279                err.add_context(format!("color_attachments[{}]", attachment_index))
2280            })?;
2281
2282            let RenderingAttachmentInfo {
2283                image_view,
2284                image_layout,
2285                resolve_info,
2286                load_op: _,
2287                store_op: _,
2288                clear_value: _,
2289                _ne: _,
2290            } = attachment_info;
2291
2292            if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
2293                return Err(Box::new(ValidationError {
2294                    context: format!("color_attachments[{}].image_view.usage()", attachment_index)
2295                        .into(),
2296                    problem: "does not contain `ImageUsage::COLOR_ATTACHMENT".into(),
2297                    vuids: &["VUID-VkRenderingInfo-colorAttachmentCount-06087"],
2298                    ..Default::default()
2299                }));
2300            }
2301
2302            if render_area_offset[0] + render_area_extent[0] > image_view.image().extent()[0] {
2303                return Err(Box::new(ValidationError {
2304                    problem: format!(
2305                        "`render_area_offset[0] + render_area_extent[0]` is greater than \
2306                        `color_attachments[{}].image_view.image().extent()[0]`",
2307                        attachment_index,
2308                    )
2309                    .into(),
2310                    vuids: &["VUID-VkRenderingInfo-pNext-06079"],
2311                    ..Default::default()
2312                }));
2313            }
2314
2315            if render_area_offset[1] + render_area_extent[1] > image_view.image().extent()[1] {
2316                return Err(Box::new(ValidationError {
2317                    problem: format!(
2318                        "`render_area_offset[1] + render_area_extent[1]` is greater than \
2319                        `color_attachments[{}].image_view.image().extent()[1]`",
2320                        attachment_index,
2321                    )
2322                    .into(),
2323                    vuids: &["VUID-VkRenderingInfo-pNext-06080"],
2324                    ..Default::default()
2325                }));
2326            }
2327
2328            match samples {
2329                Some(samples) => {
2330                    if samples != image_view.image().samples() {
2331                        return Err(Box::new(ValidationError {
2332                            problem: format!(
2333                                "`color_attachments[{0}].image_view.image().samples()` \
2334                                is not equal to the number of samples of the other attachments",
2335                                attachment_index
2336                            )
2337                            .into(),
2338                            vuids: &["VUID-VkRenderingInfo-imageView-06070"],
2339                            ..Default::default()
2340                        }));
2341                    }
2342                }
2343                None => samples = Some(image_view.image().samples()),
2344            }
2345
2346            if matches!(
2347                image_layout,
2348                ImageLayout::DepthStencilAttachmentOptimal
2349                    | ImageLayout::DepthStencilReadOnlyOptimal
2350                    | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
2351                    | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
2352                    | ImageLayout::DepthAttachmentOptimal
2353                    | ImageLayout::DepthReadOnlyOptimal
2354                    | ImageLayout::StencilAttachmentOptimal
2355                    | ImageLayout::StencilReadOnlyOptimal
2356            ) {
2357                return Err(Box::new(ValidationError {
2358                    context: format!("color_attachments[{0}].image_layout", attachment_index)
2359                        .into(),
2360                    problem: "is `ImageLayout::DepthStencilAttachmentOptimal`, \
2361                        `ImageLayout::DepthStencilReadOnlyOptimal`, \
2362                        `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`, \
2363                        `ImageLayout::DepthAttachmentStencilReadOnlyOptimal`, \
2364                        `ImageLayout::DepthAttachmentOptimal`, \
2365                        `ImageLayout::DepthReadOnlyOptimal`, \
2366                        `ImageLayout::StencilAttachmentOptimal` or \
2367                        `ImageLayout::StencilReadOnlyOptimal`"
2368                        .into(),
2369                    vuids: &[
2370                        "VUID-VkRenderingInfo-colorAttachmentCount-06090",
2371                        "VUID-VkRenderingInfo-colorAttachmentCount-06096",
2372                        "VUID-VkRenderingInfo-colorAttachmentCount-06100",
2373                    ],
2374                    ..Default::default()
2375                }));
2376            }
2377
2378            if let Some(resolve_info) = resolve_info {
2379                let &RenderingAttachmentResolveInfo {
2380                    mode: _,
2381                    image_view: _,
2382                    image_layout: resolve_image_layout,
2383                } = resolve_info;
2384
2385                if matches!(
2386                    resolve_image_layout,
2387                    ImageLayout::DepthStencilAttachmentOptimal
2388                        | ImageLayout::DepthStencilReadOnlyOptimal
2389                        | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
2390                        | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
2391                        | ImageLayout::DepthAttachmentOptimal
2392                        | ImageLayout::DepthReadOnlyOptimal
2393                        | ImageLayout::StencilAttachmentOptimal
2394                        | ImageLayout::StencilReadOnlyOptimal
2395                ) {
2396                    return Err(Box::new(ValidationError {
2397                        context: format!(
2398                            "color_attachments[{0}].resolve_info.image_layout",
2399                            attachment_index
2400                        )
2401                        .into(),
2402                        problem: "is `ImageLayout::DepthStencilAttachmentOptimal`, \
2403                            `ImageLayout::DepthStencilReadOnlyOptimal`, \
2404                            `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`, \
2405                            `ImageLayout::DepthAttachmentStencilReadOnlyOptimal`, \
2406                            `ImageLayout::DepthAttachmentOptimal`, \
2407                            `ImageLayout::DepthReadOnlyOptimal`, \
2408                            `ImageLayout::StencilAttachmentOptimal` or \
2409                            `ImageLayout::StencilReadOnlyOptimal`"
2410                            .into(),
2411                        vuids: &[
2412                            "VUID-VkRenderingInfo-colorAttachmentCount-06091",
2413                            "VUID-VkRenderingInfo-colorAttachmentCount-06097",
2414                            "VUID-VkRenderingInfo-colorAttachmentCount-06101",
2415                        ],
2416                        ..Default::default()
2417                    }));
2418                }
2419            }
2420        }
2421
2422        if let Some(attachment_info) = depth_attachment {
2423            attachment_info
2424                .validate(device)
2425                .map_err(|err| err.add_context("depth_attachment"))?;
2426
2427            let RenderingAttachmentInfo {
2428                image_view,
2429                image_layout,
2430                resolve_info,
2431                load_op: _,
2432                store_op: _,
2433                clear_value: _,
2434                _ne: _,
2435            } = attachment_info;
2436
2437            if !image_view
2438                .format()
2439                .aspects()
2440                .intersects(ImageAspects::DEPTH)
2441            {
2442                return Err(Box::new(ValidationError {
2443                    context: "depth_attachment.image_view.format()".into(),
2444                    problem: "does not have a depth aspect".into(),
2445                    vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06547"],
2446                    ..Default::default()
2447                }));
2448            }
2449
2450            if !image_view
2451                .usage()
2452                .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2453            {
2454                return Err(Box::new(ValidationError {
2455                    context: "depth_attachment.image_view.usage()".into(),
2456                    problem: "does not contain `ImageUsage::DEPTH_STENCIL_ATTACHMENT`".into(),
2457                    vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06088"],
2458                    ..Default::default()
2459                }));
2460            }
2461
2462            if render_area_offset[0] + render_area_extent[0] > image_view.image().extent()[0] {
2463                return Err(Box::new(ValidationError {
2464                    problem: "`render_area_offset[0] + render_area_extent[0]` is greater than \
2465                        `depth_attachment.image_view.image().extent()[0]`"
2466                        .into(),
2467                    vuids: &["VUID-VkRenderingInfo-pNext-06079"],
2468                    ..Default::default()
2469                }));
2470            }
2471
2472            if render_area_offset[1] + render_area_extent[1] > image_view.image().extent()[1] {
2473                return Err(Box::new(ValidationError {
2474                    problem: "`render_area_offset[1] + render_area_extent[1]` is greater than \
2475                        `depth_attachment.image_view.image().extent()[1]`"
2476                        .into(),
2477                    vuids: &["VUID-VkRenderingInfo-pNext-06080"],
2478                    ..Default::default()
2479                }));
2480            }
2481
2482            match samples {
2483                Some(samples) => {
2484                    if samples != image_view.image().samples() {
2485                        return Err(Box::new(ValidationError {
2486                            problem: "`depth_attachment.image_view.image().samples()` \
2487                                is not equal to the number of samples of the other attachments"
2488                                .into(),
2489                            vuids: &["VUID-VkRenderingInfo-imageView-06070"],
2490                            ..Default::default()
2491                        }));
2492                    }
2493                }
2494                None => samples = Some(image_view.image().samples()),
2495            }
2496
2497            if matches!(image_layout, ImageLayout::ColorAttachmentOptimal) {
2498                return Err(Box::new(ValidationError {
2499                    context: "depth_attachment.image_layout".into(),
2500                    problem: "is `ImageLayout::ColorAttachmentOptimal`".into(),
2501                    vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06092"],
2502                    ..Default::default()
2503                }));
2504            }
2505
2506            if let Some(resolve_info) = resolve_info {
2507                let &RenderingAttachmentResolveInfo {
2508                    mode,
2509                    image_view: _,
2510                    image_layout: resolve_image_layout,
2511                } = resolve_info;
2512
2513                if !properties
2514                    .supported_depth_resolve_modes
2515                    .is_some_and(|modes| modes.contains_enum(mode))
2516                {
2517                    return Err(Box::new(ValidationError {
2518                        problem: "`depth_attachment.resolve_info.mode` is not one of the modes in \
2519                            the `supported_depth_resolve_modes` device property"
2520                            .into(),
2521                        vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06102"],
2522                        ..Default::default()
2523                    }));
2524                }
2525
2526                if matches!(
2527                    resolve_image_layout,
2528                    ImageLayout::ColorAttachmentOptimal
2529                        | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
2530                ) {
2531                    return Err(Box::new(ValidationError {
2532                        context: "depth_attachment.resolve_info.image_layout".into(),
2533                        problem: "is `ImageLayout::ColorAttachmentOptimal` or \
2534                            `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`"
2535                            .into(),
2536                        vuids: &[
2537                            "VUID-VkRenderingInfo-pDepthAttachment-06093",
2538                            "VUID-VkRenderingInfo-pDepthAttachment-06098",
2539                        ],
2540                        ..Default::default()
2541                    }));
2542                }
2543            }
2544        }
2545
2546        if let Some(attachment_info) = stencil_attachment {
2547            attachment_info
2548                .validate(device)
2549                .map_err(|err| err.add_context("stencil_attachment"))?;
2550
2551            let RenderingAttachmentInfo {
2552                image_view,
2553                image_layout,
2554                resolve_info,
2555                load_op: _,
2556                store_op: _,
2557                clear_value: _,
2558                _ne: _,
2559            } = attachment_info;
2560
2561            if !image_view
2562                .format()
2563                .aspects()
2564                .intersects(ImageAspects::STENCIL)
2565            {
2566                return Err(Box::new(ValidationError {
2567                    context: "stencil_attachment.image_view.format()".into(),
2568                    problem: "does not have a stencil aspect".into(),
2569                    vuids: &["VUID-VkRenderingInfo-pStencilAttachment-06548"],
2570                    ..Default::default()
2571                }));
2572            }
2573
2574            if !image_view
2575                .usage()
2576                .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2577            {
2578                return Err(Box::new(ValidationError {
2579                    context: "stencil_attachment.image_view.usage()".into(),
2580                    problem: "does not contain `ImageUsage::DEPTH_STENCIL_ATTACHMENT`".into(),
2581                    vuids: &["VUID-VkRenderingInfo-pStencilAttachment-06089"],
2582                    ..Default::default()
2583                }));
2584            }
2585
2586            if render_area_offset[0] + render_area_extent[0] > image_view.image().extent()[0] {
2587                return Err(Box::new(ValidationError {
2588                    problem: "`render_area_offset[0] + render_area_extent[0]` is greater than \
2589                        `stencil_attachment.image_view.image().extent()[0]`"
2590                        .into(),
2591                    vuids: &["VUID-VkRenderingInfo-pNext-06079"],
2592                    ..Default::default()
2593                }));
2594            }
2595
2596            if render_area_offset[1] + render_area_extent[1] > image_view.image().extent()[1] {
2597                return Err(Box::new(ValidationError {
2598                    problem: "`render_area_offset[1] + render_area_extent[1]` is greater than \
2599                        `stencil_attachment.image_view.image().extent()[1]`"
2600                        .into(),
2601                    vuids: &["VUID-VkRenderingInfo-pNext-06080"],
2602                    ..Default::default()
2603                }));
2604            }
2605
2606            if let Some(samples) = samples {
2607                if samples != image_view.image().samples() {
2608                    return Err(Box::new(ValidationError {
2609                        problem: "`stencil_attachment.image_view.image().samples()` \
2610                            is not equal to the number of samples of the other attachments"
2611                            .into(),
2612                        vuids: &["VUID-VkRenderingInfo-imageView-06070"],
2613                        ..Default::default()
2614                    }));
2615                }
2616            }
2617
2618            if matches!(image_layout, ImageLayout::ColorAttachmentOptimal) {
2619                return Err(Box::new(ValidationError {
2620                    context: "stencil_attachment.image_layout".into(),
2621                    problem: "is `ImageLayout::ColorAttachmentOptimal`".into(),
2622                    vuids: &["VUID-VkRenderingInfo-pStencilAttachment-06094"],
2623                    ..Default::default()
2624                }));
2625            }
2626
2627            if let Some(resolve_info) = resolve_info {
2628                let &RenderingAttachmentResolveInfo {
2629                    mode,
2630                    image_view: _,
2631                    image_layout: resolve_image_layout,
2632                } = resolve_info;
2633
2634                if !properties
2635                    .supported_stencil_resolve_modes
2636                    .is_some_and(|modes| modes.contains_enum(mode))
2637                {
2638                    return Err(Box::new(ValidationError {
2639                        problem:
2640                            "`stencil_attachment.resolve_info.mode` is not one of the modes in \
2641                            the `supported_stencil_resolve_modes` device property"
2642                                .into(),
2643                        vuids: &["VUID-VkRenderingInfo-pStencilAttachment-06103"],
2644                        ..Default::default()
2645                    }));
2646                }
2647
2648                if matches!(
2649                    resolve_image_layout,
2650                    ImageLayout::ColorAttachmentOptimal
2651                        | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
2652                ) {
2653                    return Err(Box::new(ValidationError {
2654                        context: "stencil_attachment.resolve_info.image_layout".into(),
2655                        problem: "is `ImageLayout::ColorAttachmentOptimal` or \
2656                            `ImageLayout::DepthReadOnlyStencilAttachmentOptimal`"
2657                            .into(),
2658                        vuids: &[
2659                            "VUID-VkRenderingInfo-pStencilAttachment-06095",
2660                            "VUID-VkRenderingInfo-pStencilAttachment-06099",
2661                        ],
2662                        ..Default::default()
2663                    }));
2664                }
2665            }
2666        }
2667
2668        if let (Some(depth_attachment_info), Some(stencil_attachment_info)) =
2669            (depth_attachment, stencil_attachment)
2670        {
2671            if depth_attachment_info.image_view != stencil_attachment_info.image_view {
2672                return Err(Box::new(ValidationError {
2673                    problem: "`depth_attachment` and `stencil_attachment` are both `Some`, but \
2674                        `depth_attachment.image_view` does not equal \
2675                        `stencil_attachment.image_view`"
2676                        .into(),
2677                    vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06085"],
2678                    ..Default::default()
2679                }));
2680            }
2681
2682            if depth_attachment_info.image_layout != stencil_attachment_info.image_layout
2683                && !device.enabled_features().separate_depth_stencil_layouts
2684            {
2685                return Err(Box::new(ValidationError {
2686                    problem: "`depth_attachment` and `stencil_attachment` are both `Some`, and \
2687                        `depth_attachment.image_layout` does not equal \
2688                        `stencil_attachment.attachment_ref.layout`"
2689                        .into(),
2690                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2691                        "separate_depth_stencil_layouts",
2692                    )])]),
2693                    ..Default::default()
2694                }));
2695            }
2696
2697            match (
2698                &depth_attachment_info.resolve_info,
2699                &stencil_attachment_info.resolve_info,
2700            ) {
2701                (None, None) => (),
2702                (None, Some(_)) | (Some(_), None) => {
2703                    if !properties.independent_resolve_none.unwrap_or(false) {
2704                        return Err(Box::new(ValidationError {
2705                            problem: "`depth_attachment` and `stencil_attachment` are both \
2706                                `Some`, and the `independent_resolve_none` device property is \
2707                                `false`, but one of `depth_attachment.resolve_info` and \
2708                                `stencil_attachment.resolve_info` is `Some` while the other is \
2709                                `None`"
2710                                .into(),
2711                            vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06104"],
2712                            ..Default::default()
2713                        }));
2714                    }
2715                }
2716                (Some(depth_resolve_info), Some(stencil_resolve_info)) => {
2717                    if depth_resolve_info.image_layout != stencil_resolve_info.image_layout
2718                        && !device.enabled_features().separate_depth_stencil_layouts
2719                    {
2720                        return Err(Box::new(ValidationError {
2721                            problem: "`depth_attachment` and `stencil_attachment` are both \
2722                                `Some`, and `depth_attachment.resolve_info` and \
2723                                `stencil_attachment.resolve_info` are also both `Some`, and \
2724                                `depth_attachment.resolve_info.image_layout` does not equal \
2725                                `stencil_attachment.resolve_info.image_layout`"
2726                                .into(),
2727                            requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2728                                Requires::DeviceFeature("separate_depth_stencil_layouts"),
2729                            ])]),
2730                            ..Default::default()
2731                        }));
2732                    }
2733
2734                    if !properties.independent_resolve.unwrap_or(false)
2735                        && depth_resolve_info.mode != stencil_resolve_info.mode
2736                    {
2737                        return Err(Box::new(ValidationError {
2738                            problem: "`depth_attachment` and `stencil_attachment` are both \
2739                                `Some`, and `depth_attachment.resolve_info` and \
2740                                `stencil_attachment.resolve_info` are also both `Some`, and \
2741                                the `independent_resolve` device property is `false`, but \
2742                                `depth_attachment.resolve_info.mode` does not equal \
2743                                `stencil_attachment.resolve_info.mode`"
2744                                .into(),
2745                            vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06105"],
2746                            ..Default::default()
2747                        }));
2748                    }
2749
2750                    if depth_resolve_info.image_view != stencil_resolve_info.image_view {
2751                        return Err(Box::new(ValidationError {
2752                            problem: "`depth_attachment` and `stencil_attachment` are both \
2753                                `Some`, and `depth_attachment.resolve_info` and \
2754                                `stencil_attachment.resolve_info` are also both `Some`, but \
2755                                `depth_attachment.resolve_info.image_view` does not equal \
2756                                `stencil_attachment.resolve_info.image_view`"
2757                                .into(),
2758                            vuids: &["VUID-VkRenderingInfo-pDepthAttachment-06086"],
2759                            ..Default::default()
2760                        }));
2761                    }
2762                }
2763            }
2764        }
2765
2766        Ok(())
2767    }
2768
2769    pub(crate) fn to_vk<'a>(
2770        &self,
2771        fields1_vk: &'a RenderingInfoFields1Vk,
2772    ) -> ash::vk::RenderingInfo<'a> {
2773        let &Self {
2774            render_area_offset,
2775            render_area_extent,
2776            layer_count,
2777            view_mask,
2778            color_attachments: _,
2779            depth_attachment: _,
2780            stencil_attachment: _,
2781            contents,
2782            _ne: _,
2783        } = self;
2784        let RenderingInfoFields1Vk {
2785            color_attachments_vk,
2786            depth_attachment_vk,
2787            stencil_attachment_vk,
2788        } = fields1_vk;
2789
2790        ash::vk::RenderingInfo::default()
2791            .flags(contents.into())
2792            .render_area(ash::vk::Rect2D {
2793                offset: ash::vk::Offset2D {
2794                    x: render_area_offset[0] as i32,
2795                    y: render_area_offset[1] as i32,
2796                },
2797                extent: ash::vk::Extent2D {
2798                    width: render_area_extent[0],
2799                    height: render_area_extent[1],
2800                },
2801            })
2802            .layer_count(layer_count)
2803            .view_mask(view_mask)
2804            .color_attachments(color_attachments_vk)
2805            .depth_attachment(depth_attachment_vk)
2806            .stencil_attachment(stencil_attachment_vk)
2807    }
2808
2809    pub(crate) fn to_vk_fields1(&self) -> RenderingInfoFields1Vk {
2810        let Self {
2811            color_attachments,
2812            depth_attachment,
2813            stencil_attachment,
2814            ..
2815        } = self;
2816
2817        let color_attachments_vk = color_attachments
2818            .iter()
2819            .map(|attachment_info| {
2820                attachment_info.as_ref().map_or(
2821                    ash::vk::RenderingAttachmentInfo::default()
2822                        .image_view(ash::vk::ImageView::null()),
2823                    RenderingAttachmentInfo::to_vk,
2824                )
2825            })
2826            .collect();
2827
2828        let depth_attachment_vk = depth_attachment.as_ref().map_or(
2829            ash::vk::RenderingAttachmentInfo::default().image_view(ash::vk::ImageView::null()),
2830            RenderingAttachmentInfo::to_vk,
2831        );
2832
2833        let stencil_attachment_vk = stencil_attachment.as_ref().map_or(
2834            ash::vk::RenderingAttachmentInfo::default().image_view(ash::vk::ImageView::null()),
2835            RenderingAttachmentInfo::to_vk,
2836        );
2837
2838        RenderingInfoFields1Vk {
2839            color_attachments_vk,
2840            depth_attachment_vk,
2841            stencil_attachment_vk,
2842        }
2843    }
2844}
2845
2846pub(crate) struct RenderingInfoFields1Vk {
2847    pub(crate) color_attachments_vk: SmallVec<[ash::vk::RenderingAttachmentInfo<'static>; 2]>,
2848    pub(crate) depth_attachment_vk: ash::vk::RenderingAttachmentInfo<'static>,
2849    pub(crate) stencil_attachment_vk: ash::vk::RenderingAttachmentInfo<'static>,
2850}
2851
2852/// Parameters to specify properties of an attachment.
2853#[derive(Clone, Debug)]
2854pub struct RenderingAttachmentInfo {
2855    /// The image view to use as the attachment.
2856    ///
2857    /// There is no default value.
2858    pub image_view: Arc<ImageView>,
2859
2860    /// The image layout that `image_view` should be in during rendering.
2861    ///
2862    /// The default value is [`ImageLayout::ColorAttachmentOptimal`] if `image_view` has a color
2863    /// format, [`ImageLayout::DepthStencilAttachmentOptimal`] if `image_view` has a depth/stencil
2864    /// format.
2865    pub image_layout: ImageLayout,
2866
2867    /// The resolve operation that should be performed at the end of rendering.
2868    ///
2869    /// The default value is `None`.
2870    pub resolve_info: Option<RenderingAttachmentResolveInfo>,
2871
2872    /// What the implementation should do with the attachment at the start of rendering.
2873    ///
2874    /// The default value is [`AttachmentLoadOp::DontCare`].
2875    pub load_op: AttachmentLoadOp,
2876
2877    /// What the implementation should do with the attachment at the end of rendering.
2878    ///
2879    /// The default value is [`AttachmentStoreOp::DontCare`].
2880    pub store_op: AttachmentStoreOp,
2881
2882    /// If `load_op` is [`AttachmentLoadOp::Clear`],
2883    /// specifies the clear value that should be used for the attachment.
2884    ///
2885    /// If `load_op` is something else, provide `None`.
2886    ///
2887    /// The default value is `None`.
2888    pub clear_value: Option<ClearValue>,
2889
2890    pub _ne: crate::NonExhaustive,
2891}
2892
2893impl RenderingAttachmentInfo {
2894    /// Returns a `RenderingAttachmentInfo` with the specified `image_view`.
2895    #[inline]
2896    pub fn image_view(image_view: Arc<ImageView>) -> Self {
2897        let aspects = image_view.format().aspects();
2898        let image_layout = if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
2899            ImageLayout::DepthStencilAttachmentOptimal
2900        } else {
2901            ImageLayout::ColorAttachmentOptimal
2902        };
2903
2904        Self {
2905            image_view,
2906            image_layout,
2907            resolve_info: None,
2908            load_op: AttachmentLoadOp::DontCare,
2909            store_op: AttachmentStoreOp::DontCare,
2910            clear_value: None,
2911            _ne: crate::NonExhaustive(()),
2912        }
2913    }
2914
2915    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
2916        let &Self {
2917            ref image_view,
2918            image_layout,
2919            ref resolve_info,
2920            load_op,
2921            store_op,
2922            ref clear_value,
2923            _ne,
2924        } = self;
2925
2926        image_layout.validate_device(device).map_err(|err| {
2927            err.add_context("image_layout")
2928                .set_vuids(&["VUID-VkRenderingAttachmentInfo-imageLayout-parameter"])
2929        })?;
2930
2931        load_op.validate_device(device).map_err(|err| {
2932            err.add_context("load_op")
2933                .set_vuids(&["VUID-VkRenderingAttachmentInfo-loadOp-parameter"])
2934        })?;
2935
2936        store_op.validate_device(device).map_err(|err| {
2937            err.add_context("store_op")
2938                .set_vuids(&["VUID-VkRenderingAttachmentInfo-storeOp-parameter"])
2939        })?;
2940
2941        if matches!(
2942            image_layout,
2943            ImageLayout::Undefined
2944                | ImageLayout::ShaderReadOnlyOptimal
2945                | ImageLayout::TransferSrcOptimal
2946                | ImageLayout::TransferDstOptimal
2947                | ImageLayout::Preinitialized
2948                | ImageLayout::PresentSrc
2949        ) {
2950            return Err(Box::new(ValidationError {
2951                context: "image_layout".into(),
2952                problem: "is `ImageLayout::Undefined`, \
2953                    `ImageLayout::ShaderReadOnlyOptimal`, \
2954                    `ImageLayout::TransferSrcOptimal`, \
2955                    `ImageLayout::TransferDstOptimal`, \
2956                    `ImageLayout::Preinitialized` or \
2957                    `ImageLayout::PresentSrc`"
2958                    .into(),
2959                vuids: &[
2960                    "VUID-VkRenderingAttachmentInfo-imageView-06135",
2961                    "VUID-VkRenderingAttachmentInfo-imageView-06145",
2962                ],
2963                ..Default::default()
2964            }));
2965        }
2966
2967        if let Some(resolve_info) = resolve_info {
2968            resolve_info
2969                .validate(device)
2970                .map_err(|err| err.add_context("resolve_info"))?;
2971
2972            let &RenderingAttachmentResolveInfo {
2973                mode: _,
2974                image_view: ref resolve_image_view,
2975                image_layout: _,
2976            } = resolve_info;
2977
2978            if image_view.image().samples() == SampleCount::Sample1 {
2979                return Err(Box::new(ValidationError {
2980                    problem: "`resolve_info` is `Some`, but \
2981                        `image_view.image().samples()` is `SampleCount::Sample1`"
2982                        .into(),
2983                    vuids: &["VUID-VkRenderingAttachmentInfo-imageView-06132"],
2984                    ..Default::default()
2985                }));
2986            }
2987
2988            if image_view.format() != resolve_image_view.format() {
2989                return Err(Box::new(ValidationError {
2990                    problem: "`resolve_info.image_view.format()` does not equal \
2991                        `image_view.format()`"
2992                        .into(),
2993                    vuids: &["VUID-VkRenderingAttachmentInfo-imageView-06134"],
2994                    ..Default::default()
2995                }));
2996            }
2997        }
2998
2999        match (clear_value, load_op == AttachmentLoadOp::Clear) {
3000            (None, false) => (),
3001            (None, true) => {
3002                return Err(Box::new(ValidationError {
3003                    problem: "`load_op` is `AttachmentLoadOp::Clear`, but \
3004                        `clear_value` is `None`"
3005                        .into(),
3006                    ..Default::default()
3007                }));
3008            }
3009            (Some(_), false) => {
3010                return Err(Box::new(ValidationError {
3011                    problem: "`load_op` is not `AttachmentLoadOp::Clear`, but \
3012                        `clear_value` is `Some`"
3013                        .into(),
3014                    ..Default::default()
3015                }));
3016            }
3017            (Some(clear_value), true) => {
3018                clear_value
3019                    .validate(device)
3020                    .map_err(|err| err.add_context("clear_value"))?;
3021            }
3022        };
3023
3024        Ok(())
3025    }
3026
3027    pub(crate) fn to_vk(&self) -> ash::vk::RenderingAttachmentInfo<'static> {
3028        let &Self {
3029            ref image_view,
3030            image_layout,
3031            ref resolve_info,
3032            load_op,
3033            store_op,
3034            ref clear_value,
3035            _ne: _,
3036        } = self;
3037
3038        let (resolve_mode, resolve_image_view, resolve_image_layout) =
3039            resolve_info.as_ref().map_or(
3040                (
3041                    ash::vk::ResolveModeFlags::NONE,
3042                    Default::default(),
3043                    Default::default(),
3044                ),
3045                RenderingAttachmentResolveInfo::to_vk,
3046            );
3047
3048        ash::vk::RenderingAttachmentInfo::default()
3049            .image_view(image_view.handle())
3050            .image_layout(image_layout.into())
3051            .resolve_mode(resolve_mode)
3052            .resolve_image_view(resolve_image_view)
3053            .resolve_image_layout(resolve_image_layout)
3054            .load_op(load_op.into())
3055            .store_op(store_op.into())
3056            .clear_value(
3057                clear_value
3058                    .as_ref()
3059                    .map_or_else(Default::default, ClearValue::to_vk),
3060            )
3061    }
3062}
3063
3064/// Parameters to specify the resolve behavior of an attachment.
3065#[derive(Clone, Debug)]
3066pub struct RenderingAttachmentResolveInfo {
3067    /// How the resolve operation should be performed.
3068    ///
3069    /// The default value is [`ResolveMode::Average`].
3070    pub mode: ResolveMode,
3071
3072    /// The image view that the result of the resolve operation should be written to.
3073    ///
3074    /// There is no default value.
3075    pub image_view: Arc<ImageView>,
3076
3077    /// The image layout that `image_view` should be in during the resolve operation.
3078    ///
3079    /// The default value is [`ImageLayout::ColorAttachmentOptimal`] if `image_view` has a color
3080    /// format, [`ImageLayout::DepthStencilAttachmentOptimal`] if `image_view` has a depth/stencil
3081    /// format.
3082    pub image_layout: ImageLayout,
3083}
3084
3085impl RenderingAttachmentResolveInfo {
3086    /// Returns a `RenderingAttachmentResolveInfo` with the specified `image_view`.
3087    #[inline]
3088    pub fn image_view(image_view: Arc<ImageView>) -> Self {
3089        let aspects = image_view.format().aspects();
3090        let image_layout = if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
3091            ImageLayout::DepthStencilAttachmentOptimal
3092        } else {
3093            ImageLayout::ColorAttachmentOptimal
3094        };
3095
3096        Self {
3097            mode: ResolveMode::Average,
3098            image_view,
3099            image_layout,
3100        }
3101    }
3102
3103    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
3104        let &Self {
3105            mode,
3106            ref image_view,
3107            image_layout,
3108        } = self;
3109
3110        mode.validate_device(device).map_err(|err| {
3111            err.add_context("mode")
3112                .set_vuids(&["VUID-VkRenderingAttachmentInfo-resolveMode-parameter"])
3113        })?;
3114
3115        image_layout.validate_device(device).map_err(|err| {
3116            err.add_context("image_layout")
3117                .set_vuids(&["VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter"])
3118        })?;
3119
3120        if let Some(numeric_format) = image_view.format().numeric_format_color() {
3121            match numeric_format.numeric_type() {
3122                NumericType::Float => {
3123                    if mode != ResolveMode::Average {
3124                        return Err(Box::new(ValidationError {
3125                            problem: "`image_view.format()` is a floating-point color format, but \
3126                                `mode` is not `ResolveMode::Average`"
3127                                .into(),
3128                            vuids: &["VUID-VkRenderingAttachmentInfo-imageView-06129"],
3129                            ..Default::default()
3130                        }));
3131                    }
3132                }
3133                NumericType::Int | NumericType::Uint => {
3134                    if mode != ResolveMode::SampleZero {
3135                        return Err(Box::new(ValidationError {
3136                            problem: "`image_view.format()` is an integer color format, but \
3137                                `mode` is not `ResolveMode::SampleZero`"
3138                                .into(),
3139                            vuids: &["VUID-VkRenderingAttachmentInfo-imageView-06130"],
3140                            ..Default::default()
3141                        }));
3142                    }
3143                }
3144            }
3145        }
3146
3147        if image_view.image().samples() != SampleCount::Sample1 {
3148            return Err(Box::new(ValidationError {
3149                context: "image_view.image().samples()".into(),
3150                problem: "is not `SampleCount::Sample1`".into(),
3151                vuids: &["VUID-VkRenderingAttachmentInfo-imageView-06133"],
3152                ..Default::default()
3153            }));
3154        }
3155
3156        if matches!(
3157            image_layout,
3158            ImageLayout::Undefined
3159                | ImageLayout::ShaderReadOnlyOptimal
3160                | ImageLayout::TransferSrcOptimal
3161                | ImageLayout::TransferDstOptimal
3162                | ImageLayout::Preinitialized
3163                | ImageLayout::PresentSrc
3164                | ImageLayout::DepthStencilReadOnlyOptimal
3165                | ImageLayout::DepthReadOnlyOptimal
3166                | ImageLayout::StencilReadOnlyOptimal
3167        ) {
3168            return Err(Box::new(ValidationError {
3169                context: "image_layout".into(),
3170                problem: "is `ImageLayout::Undefined`, \
3171                    `ImageLayout::ShaderReadOnlyOptimal`, \
3172                    `ImageLayout::TransferSrcOptimal`, \
3173                    `ImageLayout::TransferDstOptimal`, \
3174                    `ImageLayout::Preinitialized`, \
3175                    `ImageLayout::PresentSrc`, \
3176                    `ImageLayout::DepthStencilReadOnlyOptimal`, \
3177                    `ImageLayout::DepthReadOnlyOptimal` or \
3178                    `ImageLayout::StencilReadOnlyOptimal`"
3179                    .into(),
3180                vuids: &[
3181                    "VUID-VkRenderingAttachmentInfo-imageView-06136",
3182                    "VUID-VkRenderingAttachmentInfo-imageView-06137",
3183                    "VUID-VkRenderingAttachmentInfo-imageView-06146",
3184                ],
3185                ..Default::default()
3186            }));
3187        }
3188
3189        Ok(())
3190    }
3191
3192    pub(crate) fn to_vk(
3193        &self,
3194    ) -> (
3195        ash::vk::ResolveModeFlags,
3196        ash::vk::ImageView,
3197        ash::vk::ImageLayout,
3198    ) {
3199        let &Self {
3200            mode,
3201            ref image_view,
3202            image_layout,
3203        } = self;
3204
3205        (mode.into(), image_view.handle(), image_layout.into())
3206    }
3207}
3208
3209/// Clear attachment type, used in [`clear_attachments`] command.
3210///
3211/// [`clear_attachments`]: AutoCommandBufferBuilder::clear_attachments
3212#[derive(Clone, Copy, Debug)]
3213pub enum ClearAttachment {
3214    /// Clear the color attachment at the specified index, with the specified clear value.
3215    Color {
3216        color_attachment: u32,
3217        clear_value: ClearColorValue,
3218    },
3219
3220    /// Clear the depth attachment with the specified depth value.
3221    Depth(f32),
3222
3223    /// Clear the stencil attachment with the specified stencil value.
3224    Stencil(u32),
3225
3226    /// Clear the depth and stencil attachments with the specified depth and stencil values.
3227    DepthStencil((f32, u32)),
3228}
3229
3230impl ClearAttachment {
3231    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
3232        if let ClearAttachment::Depth(depth) | ClearAttachment::DepthStencil((depth, _)) = self {
3233            if !(0.0..=1.0).contains(depth)
3234                && !device.enabled_extensions().ext_depth_range_unrestricted
3235            {
3236                return Err(Box::new(ValidationError {
3237                    problem: "is `ClearAttachment::Depth` or `ClearAttachment::DepthStencil`, and \
3238                        the depth value is not between 0.0 and 1.0 inclusive"
3239                        .into(),
3240                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
3241                        "ext_depth_range_unrestricted",
3242                    )])]),
3243                    vuids: &["VUID-VkClearDepthStencilValue-depth-00022"],
3244                    ..Default::default()
3245                }));
3246            }
3247        }
3248
3249        Ok(())
3250    }
3251
3252    #[allow(clippy::wrong_self_convention)]
3253    #[doc(hidden)]
3254    pub fn to_vk(&self) -> ash::vk::ClearAttachment {
3255        match *self {
3256            ClearAttachment::Color {
3257                color_attachment,
3258                clear_value,
3259            } => ash::vk::ClearAttachment {
3260                aspect_mask: ash::vk::ImageAspectFlags::COLOR,
3261                color_attachment,
3262                clear_value: ash::vk::ClearValue {
3263                    color: clear_value.to_vk(),
3264                },
3265            },
3266            ClearAttachment::Depth(depth) => ash::vk::ClearAttachment {
3267                aspect_mask: ash::vk::ImageAspectFlags::DEPTH,
3268                color_attachment: 0,
3269                clear_value: ash::vk::ClearValue {
3270                    depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil: 0 },
3271                },
3272            },
3273            ClearAttachment::Stencil(stencil) => ash::vk::ClearAttachment {
3274                aspect_mask: ash::vk::ImageAspectFlags::STENCIL,
3275                color_attachment: 0,
3276                clear_value: ash::vk::ClearValue {
3277                    depth_stencil: ash::vk::ClearDepthStencilValue {
3278                        depth: 0.0,
3279                        stencil,
3280                    },
3281                },
3282            },
3283            ClearAttachment::DepthStencil((depth, stencil)) => ash::vk::ClearAttachment {
3284                aspect_mask: ash::vk::ImageAspectFlags::DEPTH | ash::vk::ImageAspectFlags::STENCIL,
3285                color_attachment: 0,
3286                clear_value: ash::vk::ClearValue {
3287                    depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
3288                },
3289            },
3290        }
3291    }
3292}
3293
3294/// Specifies the clear region for the [`clear_attachments`] command.
3295///
3296/// [`clear_attachments`]: AutoCommandBufferBuilder::clear_attachments
3297#[derive(Clone, Debug, PartialEq, Eq)]
3298pub struct ClearRect {
3299    /// The rectangle offset.
3300    pub offset: [u32; 2],
3301
3302    /// The width and height of the rectangle.
3303    pub extent: [u32; 2],
3304
3305    /// The range of array layers to be cleared.
3306    pub array_layers: Range<u32>,
3307}
3308
3309impl ClearRect {
3310    #[doc(hidden)]
3311    pub fn to_vk(&self) -> ash::vk::ClearRect {
3312        let &Self {
3313            offset,
3314            extent,
3315            ref array_layers,
3316        } = self;
3317
3318        ash::vk::ClearRect {
3319            rect: ash::vk::Rect2D {
3320                offset: ash::vk::Offset2D {
3321                    x: offset[0] as i32,
3322                    y: offset[1] as i32,
3323                },
3324                extent: ash::vk::Extent2D {
3325                    width: extent[0],
3326                    height: extent[1],
3327                },
3328            },
3329            base_array_layer: array_layers.start,
3330            layer_count: array_layers.end - array_layers.start,
3331        }
3332    }
3333}