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
24impl<L> AutoCommandBufferBuilder<L> {
28 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 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 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 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 ..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 ..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 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 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 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 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 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 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 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 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 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 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 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 ..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 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 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 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 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#[derive(Clone, Debug)]
1692pub struct RenderPassBeginInfo {
1693 pub render_pass: Arc<RenderPass>,
1700
1701 pub framebuffer: Arc<Framebuffer>,
1705
1706 pub render_area_offset: [u32; 2],
1710
1711 pub render_area_extent: [u32; 2],
1718
1719 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 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 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#[derive(Clone, Debug)]
1925pub struct SubpassBeginInfo {
1926 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#[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#[derive(Clone, Debug)]
1994pub struct RenderingInfo {
1995 pub render_area_offset: [u32; 2],
2001
2002 pub render_area_extent: [u32; 2],
2012
2013 pub layer_count: u32,
2024
2025 pub view_mask: u32,
2034
2035 pub color_attachments: Vec<Option<RenderingAttachmentInfo>>,
2043
2044 pub depth_attachment: Option<RenderingAttachmentInfo>,
2051
2052 pub stencil_attachment: Option<RenderingAttachmentInfo>,
2059
2060 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 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 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 ..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#[derive(Clone, Debug)]
2854pub struct RenderingAttachmentInfo {
2855 pub image_view: Arc<ImageView>,
2859
2860 pub image_layout: ImageLayout,
2866
2867 pub resolve_info: Option<RenderingAttachmentResolveInfo>,
2871
2872 pub load_op: AttachmentLoadOp,
2876
2877 pub store_op: AttachmentStoreOp,
2881
2882 pub clear_value: Option<ClearValue>,
2889
2890 pub _ne: crate::NonExhaustive,
2891}
2892
2893impl RenderingAttachmentInfo {
2894 #[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#[derive(Clone, Debug)]
3066pub struct RenderingAttachmentResolveInfo {
3067 pub mode: ResolveMode,
3071
3072 pub image_view: Arc<ImageView>,
3076
3077 pub image_layout: ImageLayout,
3083}
3084
3085impl RenderingAttachmentResolveInfo {
3086 #[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#[derive(Clone, Copy, Debug)]
3213pub enum ClearAttachment {
3214 Color {
3216 color_attachment: u32,
3217 clear_value: ClearColorValue,
3218 },
3219
3220 Depth(f32),
3222
3223 Stencil(u32),
3225
3226 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#[derive(Clone, Debug, PartialEq, Eq)]
3298pub struct ClearRect {
3299 pub offset: [u32; 2],
3301
3302 pub extent: [u32; 2],
3304
3305 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}