1 // Copyright (c) 2022 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9
10 use super::{
11 BeginRenderPassState, BeginRenderingState, ClearAttachment, ClearRect, CommandBufferBuilder,
12 RenderPassBeginInfo, RenderPassError, RenderPassState, RenderPassStateAttachmentInfo,
13 RenderPassStateAttachmentResolveInfo, RenderPassStateAttachments, RenderPassStateType,
14 RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, ResourcesState,
15 };
16 use crate::{
17 command_buffer::{
18 allocator::CommandBufferAllocator, PrimaryCommandBuffer, ResourceInCommand, ResourceUseRef,
19 SubpassContents,
20 },
21 device::{DeviceOwned, QueueFlags},
22 format::{ClearColorValue, ClearValue, NumericType},
23 image::{ImageAspects, ImageLayout, ImageUsage, SampleCount},
24 pipeline::graphics::render_pass::PipelineRenderingCreateInfo,
25 render_pass::{AttachmentDescription, LoadOp, ResolveMode, SubpassDescription},
26 sync::PipelineStageAccess,
27 RequiresOneOf, Version, VulkanObject,
28 };
29 use smallvec::SmallVec;
30 use std::cmp::min;
31
32 impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A>
33 where
34 A: CommandBufferAllocator,
35 {
36 /// Begins a render pass using a render pass object and framebuffer.
37 ///
38 /// You must call this or `begin_rendering` before you can record draw commands.
39 ///
40 /// `contents` specifies what kinds of commands will be recorded in the render pass, either
41 /// draw commands or executions of secondary command buffers.
42 ///
43 /// # Safety
44 ///
45 /// - Appropriate synchronization must be provided for all images
46 /// that are accessed by the command.
47 /// - All images that are accessed by the command must be in the expected image layout.
48 #[inline]
begin_render_pass( &mut self, render_pass_begin_info: RenderPassBeginInfo, contents: SubpassContents, ) -> Result<&mut Self, RenderPassError>49 pub unsafe fn begin_render_pass(
50 &mut self,
51 render_pass_begin_info: RenderPassBeginInfo,
52 contents: SubpassContents,
53 ) -> Result<&mut Self, RenderPassError> {
54 self.validate_begin_render_pass(&render_pass_begin_info, contents)?;
55
56 unsafe { Ok(self.begin_render_pass_unchecked(render_pass_begin_info, contents)) }
57 }
58
validate_begin_render_pass( &self, render_pass_begin_info: &RenderPassBeginInfo, contents: SubpassContents, ) -> Result<(), RenderPassError>59 fn validate_begin_render_pass(
60 &self,
61 render_pass_begin_info: &RenderPassBeginInfo,
62 contents: SubpassContents,
63 ) -> Result<(), RenderPassError> {
64 let device = self.device();
65
66 // VUID-VkSubpassBeginInfo-contents-parameter
67 contents.validate_device(device)?;
68
69 let queue_family_properties = self.queue_family_properties();
70
71 // VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool
72 if !queue_family_properties
73 .queue_flags
74 .intersects(QueueFlags::GRAPHICS)
75 {
76 return Err(RenderPassError::NotSupportedByQueueFamily);
77 }
78
79 // VUID-vkCmdBeginRenderPass2-renderpass
80 if self.builder_state.render_pass.is_some() {
81 return Err(RenderPassError::ForbiddenInsideRenderPass);
82 }
83
84 let RenderPassBeginInfo {
85 render_pass,
86 framebuffer,
87 render_area_offset,
88 render_area_extent,
89 clear_values,
90 _ne: _,
91 } = render_pass_begin_info;
92
93 // VUID-VkRenderPassBeginInfo-commonparent
94 // VUID-vkCmdBeginRenderPass2-framebuffer-02779
95 assert_eq!(device, framebuffer.device());
96
97 // VUID-VkRenderPassBeginInfo-renderPass-00904
98 if !render_pass.is_compatible_with(framebuffer.render_pass()) {
99 return Err(RenderPassError::FramebufferNotCompatible);
100 }
101
102 for i in 0..2 {
103 // VUID-VkRenderPassBeginInfo-pNext-02852
104 // VUID-VkRenderPassBeginInfo-pNext-02853
105 if render_area_offset[i] + render_area_extent[i] > framebuffer.extent()[i] {
106 return Err(RenderPassError::RenderAreaOutOfBounds);
107 }
108 }
109
110 for (attachment_index, (attachment_desc, image_view)) in render_pass
111 .attachments()
112 .iter()
113 .zip(framebuffer.attachments())
114 .enumerate()
115 {
116 let attachment_index = attachment_index as u32;
117 let &AttachmentDescription {
118 initial_layout,
119 final_layout,
120 ..
121 } = attachment_desc;
122
123 for layout in [initial_layout, final_layout] {
124 match layout {
125 ImageLayout::ColorAttachmentOptimal => {
126 // VUID-vkCmdBeginRenderPass2-initialLayout-03094
127 if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
128 return Err(RenderPassError::AttachmentImageMissingUsage {
129 attachment_index,
130 usage: "color_attachment",
131 });
132 }
133 }
134 ImageLayout::DepthReadOnlyStencilAttachmentOptimal
135 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
136 | ImageLayout::DepthStencilAttachmentOptimal
137 | ImageLayout::DepthStencilReadOnlyOptimal => {
138 // VUID-vkCmdBeginRenderPass2-initialLayout-03096
139 if !image_view
140 .usage()
141 .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
142 {
143 return Err(RenderPassError::AttachmentImageMissingUsage {
144 attachment_index,
145 usage: "depth_stencil_attachment",
146 });
147 }
148 }
149 ImageLayout::ShaderReadOnlyOptimal => {
150 // VUID-vkCmdBeginRenderPass2-initialLayout-03097
151 if !image_view
152 .usage()
153 .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
154 {
155 return Err(RenderPassError::AttachmentImageMissingUsage {
156 attachment_index,
157 usage: "sampled or input_attachment",
158 });
159 }
160 }
161 ImageLayout::TransferSrcOptimal => {
162 // VUID-vkCmdBeginRenderPass2-initialLayout-03098
163 if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
164 return Err(RenderPassError::AttachmentImageMissingUsage {
165 attachment_index,
166 usage: "transfer_src",
167 });
168 }
169 }
170 ImageLayout::TransferDstOptimal => {
171 // VUID-vkCmdBeginRenderPass2-initialLayout-03099
172 if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
173 return Err(RenderPassError::AttachmentImageMissingUsage {
174 attachment_index,
175 usage: "transfer_dst",
176 });
177 }
178 }
179 _ => (),
180 }
181 }
182 }
183
184 for subpass_desc in render_pass.subpasses() {
185 let SubpassDescription {
186 view_mask: _,
187 input_attachments,
188 color_attachments,
189 resolve_attachments,
190 depth_stencil_attachment,
191 preserve_attachments: _,
192 _ne: _,
193 } = subpass_desc;
194
195 for atch_ref in (input_attachments.iter())
196 .chain(color_attachments)
197 .chain(resolve_attachments)
198 .chain([depth_stencil_attachment])
199 .flatten()
200 {
201 let image_view = &framebuffer.attachments()[atch_ref.attachment as usize];
202
203 match atch_ref.layout {
204 ImageLayout::ColorAttachmentOptimal => {
205 // VUID-vkCmdBeginRenderPass2-initialLayout-03094
206 if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
207 return Err(RenderPassError::AttachmentImageMissingUsage {
208 attachment_index: atch_ref.attachment,
209 usage: "color_attachment",
210 });
211 }
212 }
213 ImageLayout::DepthReadOnlyStencilAttachmentOptimal
214 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
215 | ImageLayout::DepthStencilAttachmentOptimal
216 | ImageLayout::DepthStencilReadOnlyOptimal => {
217 // VUID-vkCmdBeginRenderPass2-initialLayout-03096
218 if !image_view
219 .usage()
220 .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
221 {
222 return Err(RenderPassError::AttachmentImageMissingUsage {
223 attachment_index: atch_ref.attachment,
224 usage: "depth_stencil_attachment",
225 });
226 }
227 }
228 ImageLayout::ShaderReadOnlyOptimal => {
229 // VUID-vkCmdBeginRenderPass2-initialLayout-03097
230 if !image_view
231 .usage()
232 .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
233 {
234 return Err(RenderPassError::AttachmentImageMissingUsage {
235 attachment_index: atch_ref.attachment,
236 usage: "sampled or input_attachment",
237 });
238 }
239 }
240 ImageLayout::TransferSrcOptimal => {
241 // VUID-vkCmdBeginRenderPass2-initialLayout-03098
242 if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
243 return Err(RenderPassError::AttachmentImageMissingUsage {
244 attachment_index: atch_ref.attachment,
245 usage: "transfer_src",
246 });
247 }
248 }
249 ImageLayout::TransferDstOptimal => {
250 // VUID-vkCmdBeginRenderPass2-initialLayout-03099
251 if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
252 return Err(RenderPassError::AttachmentImageMissingUsage {
253 attachment_index: atch_ref.attachment,
254 usage: "transfer_dst",
255 });
256 }
257 }
258 _ => (),
259 }
260 }
261 }
262
263 // VUID-VkRenderPassBeginInfo-clearValueCount-00902
264 if clear_values.len() < render_pass.attachments().len() {
265 return Err(RenderPassError::ClearValueMissing {
266 attachment_index: clear_values.len() as u32,
267 });
268 }
269
270 // VUID-VkRenderPassBeginInfo-clearValueCount-04962
271 for (attachment_index, (attachment_desc, &clear_value)) in render_pass
272 .attachments()
273 .iter()
274 .zip(clear_values)
275 .enumerate()
276 {
277 let attachment_index = attachment_index as u32;
278 let attachment_format = attachment_desc.format.unwrap();
279
280 if attachment_desc.load_op == LoadOp::Clear
281 || attachment_desc.stencil_load_op == LoadOp::Clear
282 {
283 let clear_value = match clear_value {
284 Some(x) => x,
285 None => return Err(RenderPassError::ClearValueMissing { attachment_index }),
286 };
287
288 if let (Some(numeric_type), LoadOp::Clear) =
289 (attachment_format.type_color(), attachment_desc.load_op)
290 {
291 match numeric_type {
292 NumericType::SFLOAT
293 | NumericType::UFLOAT
294 | NumericType::SNORM
295 | NumericType::UNORM
296 | NumericType::SSCALED
297 | NumericType::USCALED
298 | NumericType::SRGB => {
299 if !matches!(clear_value, ClearValue::Float(_)) {
300 return Err(RenderPassError::ClearValueNotCompatible {
301 clear_value,
302 attachment_index,
303 attachment_format,
304 });
305 }
306 }
307 NumericType::SINT => {
308 if !matches!(clear_value, ClearValue::Int(_)) {
309 return Err(RenderPassError::ClearValueNotCompatible {
310 clear_value,
311 attachment_index,
312 attachment_format,
313 });
314 }
315 }
316 NumericType::UINT => {
317 if !matches!(clear_value, ClearValue::Uint(_)) {
318 return Err(RenderPassError::ClearValueNotCompatible {
319 clear_value,
320 attachment_index,
321 attachment_format,
322 });
323 }
324 }
325 }
326 } else {
327 let attachment_aspects = attachment_format.aspects();
328 let need_depth = attachment_aspects.intersects(ImageAspects::DEPTH)
329 && attachment_desc.load_op == LoadOp::Clear;
330 let need_stencil = attachment_aspects.intersects(ImageAspects::STENCIL)
331 && attachment_desc.stencil_load_op == LoadOp::Clear;
332
333 if need_depth && need_stencil {
334 if !matches!(clear_value, ClearValue::DepthStencil(_)) {
335 return Err(RenderPassError::ClearValueNotCompatible {
336 clear_value,
337 attachment_index,
338 attachment_format,
339 });
340 }
341 } else if need_depth {
342 if !matches!(clear_value, ClearValue::Depth(_)) {
343 return Err(RenderPassError::ClearValueNotCompatible {
344 clear_value,
345 attachment_index,
346 attachment_format,
347 });
348 }
349 } else if need_stencil {
350 if !matches!(clear_value, ClearValue::Stencil(_)) {
351 return Err(RenderPassError::ClearValueNotCompatible {
352 clear_value,
353 attachment_index,
354 attachment_format,
355 });
356 }
357 }
358 }
359 }
360 }
361
362 // VUID-vkCmdBeginRenderPass2-initialLayout-03100
363 // TODO:
364
365 // VUID-vkCmdBeginRenderPass2-srcStageMask-06453
366 // TODO:
367
368 // VUID-vkCmdBeginRenderPass2-dstStageMask-06454
369 // TODO:
370
371 // VUID-vkCmdBeginRenderPass2-framebuffer-02533
372 // For any attachment in framebuffer that is used by renderPass and is bound to memory locations that are also bound to another attachment used by renderPass, and if at least one of those uses causes either
373 // attachment to be written to, both attachments must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set
374
375 // TODO: sync check
376
377 Ok(())
378 }
379
380 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
begin_render_pass_unchecked( &mut self, render_pass_begin_info: RenderPassBeginInfo, contents: SubpassContents, ) -> &mut Self381 pub unsafe fn begin_render_pass_unchecked(
382 &mut self,
383 render_pass_begin_info: RenderPassBeginInfo,
384 contents: SubpassContents,
385 ) -> &mut Self {
386 let RenderPassBeginInfo {
387 render_pass,
388 framebuffer,
389 render_area_offset,
390 render_area_extent,
391 clear_values,
392 _ne: _,
393 } = render_pass_begin_info;
394
395 let clear_values_vk: SmallVec<[_; 4]> = clear_values
396 .iter()
397 .copied()
398 .map(|clear_value| clear_value.map(Into::into).unwrap_or_default())
399 .collect();
400
401 let render_pass_begin_info = ash::vk::RenderPassBeginInfo {
402 render_pass: render_pass.handle(),
403 framebuffer: framebuffer.handle(),
404 render_area: ash::vk::Rect2D {
405 offset: ash::vk::Offset2D {
406 x: render_area_offset[0] as i32,
407 y: render_area_offset[1] as i32,
408 },
409 extent: ash::vk::Extent2D {
410 width: render_area_extent[0],
411 height: render_area_extent[1],
412 },
413 },
414 clear_value_count: clear_values_vk.len() as u32,
415 p_clear_values: clear_values_vk.as_ptr(),
416 ..Default::default()
417 };
418
419 let subpass_begin_info = ash::vk::SubpassBeginInfo {
420 contents: contents.into(),
421 ..Default::default()
422 };
423
424 let fns = self.device().fns();
425
426 if self.device().api_version() >= Version::V1_2
427 || self.device().enabled_extensions().khr_create_renderpass2
428 {
429 if self.device().api_version() >= Version::V1_2 {
430 (fns.v1_2.cmd_begin_render_pass2)(
431 self.handle(),
432 &render_pass_begin_info,
433 &subpass_begin_info,
434 );
435 } else {
436 (fns.khr_create_renderpass2.cmd_begin_render_pass2_khr)(
437 self.handle(),
438 &render_pass_begin_info,
439 &subpass_begin_info,
440 );
441 }
442 } else {
443 debug_assert!(subpass_begin_info.p_next.is_null());
444
445 (fns.v1_0.cmd_begin_render_pass)(
446 self.handle(),
447 &render_pass_begin_info,
448 subpass_begin_info.contents,
449 );
450 }
451
452 let command_index = self.next_command_index;
453 let command_name = "begin_render_pass";
454
455 // Advance to first subpass
456 {
457 let subpass = render_pass.clone().first_subpass();
458 self.builder_state.render_pass = Some(RenderPassState {
459 contents,
460 render_area_offset,
461 render_area_extent,
462
463 rendering_info: PipelineRenderingCreateInfo::from_subpass(&subpass),
464 attachments: Some(RenderPassStateAttachments::from_subpass(
465 &subpass,
466 &framebuffer,
467 )),
468
469 render_pass: BeginRenderPassState {
470 subpass,
471 framebuffer: Some(framebuffer.clone()),
472 }
473 .into(),
474 });
475 }
476
477 // Start of first subpass
478 {
479 // TODO: Apply barriers and layout transitions
480
481 let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
482 record_subpass_attachments_load(
483 &mut self.resources_usage_state,
484 command_index,
485 command_name,
486 render_pass_state,
487 );
488 }
489
490 self.resources.push(Box::new(render_pass));
491 self.resources.push(Box::new(framebuffer));
492
493 self.next_command_index += 1;
494 self
495 }
496
497 /// Advances to the next subpass of the render pass previously begun with `begin_render_pass`.
498 ///
499 /// # Safety
500 ///
501 /// - Appropriate synchronization must be provided for all images
502 /// that are accessed by the command.
503 /// - All images that are accessed by the command must be in the expected image layout.
504 #[inline]
next_subpass( &mut self, contents: SubpassContents, ) -> Result<&mut Self, RenderPassError>505 pub unsafe fn next_subpass(
506 &mut self,
507 contents: SubpassContents,
508 ) -> Result<&mut Self, RenderPassError> {
509 self.validate_next_subpass(contents)?;
510
511 unsafe { Ok(self.next_subpass_unchecked(contents)) }
512 }
513
validate_next_subpass(&self, contents: SubpassContents) -> Result<(), RenderPassError>514 fn validate_next_subpass(&self, contents: SubpassContents) -> Result<(), RenderPassError> {
515 let device = self.device();
516
517 // VUID-VkSubpassBeginInfo-contents-parameter
518 contents.validate_device(device)?;
519
520 // VUID-vkCmdNextSubpass2-renderpass
521 let render_pass_state = self
522 .builder_state
523 .render_pass
524 .as_ref()
525 .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
526
527 let begin_render_pass_state = match &render_pass_state.render_pass {
528 RenderPassStateType::BeginRenderPass(state) => state,
529 RenderPassStateType::BeginRendering(_) => {
530 return Err(RenderPassError::ForbiddenWithBeginRendering)
531 }
532 };
533
534 // VUID-vkCmdNextSubpass2-None-03102
535 if begin_render_pass_state.subpass.is_last_subpass() {
536 return Err(RenderPassError::NoSubpassesRemaining {
537 current_subpass: begin_render_pass_state.subpass.index(),
538 });
539 }
540
541 // VUID?
542 if self
543 .builder_state
544 .queries
545 .values()
546 .any(|state| state.in_subpass)
547 {
548 return Err(RenderPassError::QueryIsActive);
549 }
550
551 // VUID-vkCmdNextSubpass2-commandBuffer-cmdpool
552 debug_assert!(self
553 .queue_family_properties()
554 .queue_flags
555 .intersects(QueueFlags::GRAPHICS));
556
557 // VUID-vkCmdNextSubpass2-bufferlevel
558 // Ensured by the type of the impl block
559
560 // TODO: sync check
561
562 Ok(())
563 }
564
565 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
next_subpass_unchecked(&mut self, contents: SubpassContents) -> &mut Self566 pub unsafe fn next_subpass_unchecked(&mut self, contents: SubpassContents) -> &mut Self {
567 let subpass_begin_info = ash::vk::SubpassBeginInfo {
568 contents: contents.into(),
569 ..Default::default()
570 };
571
572 let subpass_end_info = ash::vk::SubpassEndInfo::default();
573
574 let fns = self.device().fns();
575
576 if self.device().api_version() >= Version::V1_2
577 || self.device().enabled_extensions().khr_create_renderpass2
578 {
579 if self.device().api_version() >= Version::V1_2 {
580 (fns.v1_2.cmd_next_subpass2)(self.handle(), &subpass_begin_info, &subpass_end_info);
581 } else {
582 (fns.khr_create_renderpass2.cmd_next_subpass2_khr)(
583 self.handle(),
584 &subpass_begin_info,
585 &subpass_end_info,
586 );
587 }
588 } else {
589 (fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info.contents);
590 }
591
592 let command_index = self.next_command_index;
593 let command_name = "next_subpass";
594
595 // End of previous subpass
596 {
597 let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
598 record_subpass_attachments_resolve(
599 &mut self.resources_usage_state,
600 command_index,
601 command_name,
602 render_pass_state,
603 );
604 record_subpass_attachments_store(
605 &mut self.resources_usage_state,
606 command_index,
607 command_name,
608 render_pass_state,
609 );
610 }
611
612 // Advance to next subpass
613 {
614 let render_pass_state = self.builder_state.render_pass.as_mut().unwrap();
615 let begin_render_pass_state = match &mut render_pass_state.render_pass {
616 RenderPassStateType::BeginRenderPass(x) => x,
617 _ => unreachable!(),
618 };
619
620 begin_render_pass_state.subpass.next_subpass();
621 render_pass_state.contents = contents;
622 render_pass_state.rendering_info =
623 PipelineRenderingCreateInfo::from_subpass(&begin_render_pass_state.subpass);
624 render_pass_state.attachments = Some(RenderPassStateAttachments::from_subpass(
625 &begin_render_pass_state.subpass,
626 begin_render_pass_state.framebuffer.as_ref().unwrap(),
627 ));
628
629 if render_pass_state.rendering_info.view_mask != 0 {
630 // When multiview is enabled, at the beginning of each subpass, all
631 // non-render pass state is undefined.
632 self.builder_state = Default::default();
633 }
634 }
635
636 // Start of next subpass
637 {
638 // TODO: Apply barriers and layout transitions
639
640 let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
641 record_subpass_attachments_load(
642 &mut self.resources_usage_state,
643 command_index,
644 command_name,
645 render_pass_state,
646 );
647 }
648
649 self.next_command_index += 1;
650 self
651 }
652
653 /// Ends the render pass previously begun with `begin_render_pass`.
654 ///
655 /// This must be called after you went through all the subpasses.
656 ///
657 /// # Safety
658 ///
659 /// - Appropriate synchronization must be provided for all images
660 /// that are accessed by the command.
661 /// - All images that are accessed by the command must be in the expected image layout.
662 #[inline]
end_render_pass(&mut self) -> Result<&mut Self, RenderPassError>663 pub unsafe fn end_render_pass(&mut self) -> Result<&mut Self, RenderPassError> {
664 self.validate_end_render_pass()?;
665
666 unsafe { Ok(self.end_render_pass_unchecked()) }
667 }
668
validate_end_render_pass(&self) -> Result<(), RenderPassError>669 fn validate_end_render_pass(&self) -> Result<(), RenderPassError> {
670 // VUID-vkCmdEndRenderPass2-renderpass
671 let render_pass_state = self
672 .builder_state
673 .render_pass
674 .as_ref()
675 .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
676
677 let begin_render_pass_state = match &render_pass_state.render_pass {
678 RenderPassStateType::BeginRenderPass(state) => state,
679 RenderPassStateType::BeginRendering(_) => {
680 return Err(RenderPassError::ForbiddenWithBeginRendering)
681 }
682 };
683
684 // VUID-vkCmdEndRenderPass2-None-03103
685 if !begin_render_pass_state.subpass.is_last_subpass() {
686 return Err(RenderPassError::SubpassesRemaining {
687 current_subpass: begin_render_pass_state.subpass.index(),
688 remaining_subpasses: begin_render_pass_state
689 .subpass
690 .render_pass()
691 .subpasses()
692 .len() as u32
693 - begin_render_pass_state.subpass.index(),
694 });
695 }
696
697 // VUID?
698 if self
699 .builder_state
700 .queries
701 .values()
702 .any(|state| state.in_subpass)
703 {
704 return Err(RenderPassError::QueryIsActive);
705 }
706
707 // VUID-vkCmdEndRenderPass2-commandBuffer-cmdpool
708 debug_assert!(self
709 .queue_family_properties()
710 .queue_flags
711 .intersects(QueueFlags::GRAPHICS));
712
713 // VUID-vkCmdEndRenderPass2-bufferlevel
714 // Ensured by the type of the impl block
715
716 // TODO: sync check
717
718 Ok(())
719 }
720
721 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
end_render_pass_unchecked(&mut self) -> &mut Self722 pub unsafe fn end_render_pass_unchecked(&mut self) -> &mut Self {
723 let subpass_end_info = ash::vk::SubpassEndInfo::default();
724
725 let fns = self.device().fns();
726
727 if self.device().api_version() >= Version::V1_2
728 || self.device().enabled_extensions().khr_create_renderpass2
729 {
730 if self.device().api_version() >= Version::V1_2 {
731 (fns.v1_2.cmd_end_render_pass2)(self.handle(), &subpass_end_info);
732 } else {
733 (fns.khr_create_renderpass2.cmd_end_render_pass2_khr)(
734 self.handle(),
735 &subpass_end_info,
736 );
737 }
738 } else {
739 (fns.v1_0.cmd_end_render_pass)(self.handle());
740 }
741
742 let command_index = self.next_command_index;
743 let command_name = "end_render_pass";
744
745 // End of last subpass
746 {
747 let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
748 record_subpass_attachments_resolve(
749 &mut self.resources_usage_state,
750 command_index,
751 command_name,
752 render_pass_state,
753 );
754 record_subpass_attachments_store(
755 &mut self.resources_usage_state,
756 command_index,
757 command_name,
758 render_pass_state,
759 );
760 }
761
762 // TODO: Apply barriers and layout transitions
763
764 self.builder_state.render_pass = None;
765
766 self.next_command_index += 1;
767 self
768 }
769 }
770
771 impl<L, A> CommandBufferBuilder<L, A>
772 where
773 A: CommandBufferAllocator,
774 {
775 /// Begins a render pass without a render pass object or framebuffer.
776 ///
777 /// You must call this or `begin_render_pass` before you can record draw commands.
778 ///
779 /// # Safety
780 ///
781 /// - Appropriate synchronization must be provided for all images
782 /// that are accessed by the command.
783 /// - All images that are accessed by the command must be in the expected image layout.
784 #[inline]
begin_rendering( &mut self, mut rendering_info: RenderingInfo, ) -> Result<&mut Self, RenderPassError>785 pub unsafe fn begin_rendering(
786 &mut self,
787 mut rendering_info: RenderingInfo,
788 ) -> Result<&mut Self, RenderPassError> {
789 rendering_info.set_extent_layers()?;
790 self.validate_begin_rendering(&rendering_info)?;
791
792 unsafe { Ok(self.begin_rendering_unchecked(rendering_info)) }
793 }
794
validate_begin_rendering( &self, rendering_info: &RenderingInfo, ) -> Result<(), RenderPassError>795 fn validate_begin_rendering(
796 &self,
797 rendering_info: &RenderingInfo,
798 ) -> Result<(), RenderPassError> {
799 let device = self.device();
800 let properties = device.physical_device().properties();
801
802 // VUID-vkCmdBeginRendering-dynamicRendering-06446
803 if !device.enabled_features().dynamic_rendering {
804 return Err(RenderPassError::RequirementNotMet {
805 required_for: "`CommandBufferBuilder::begin_rendering`",
806 requires_one_of: RequiresOneOf {
807 features: &["dynamic_rendering"],
808 ..Default::default()
809 },
810 });
811 }
812
813 let queue_family_properties = self.queue_family_properties();
814
815 // VUID-vkCmdBeginRendering-commandBuffer-cmdpool
816 if !queue_family_properties
817 .queue_flags
818 .intersects(QueueFlags::GRAPHICS)
819 {
820 return Err(RenderPassError::NotSupportedByQueueFamily);
821 }
822
823 // VUID-vkCmdBeginRendering-renderpass
824 if self.builder_state.render_pass.is_some() {
825 return Err(RenderPassError::ForbiddenInsideRenderPass);
826 }
827
828 let &RenderingInfo {
829 render_area_offset,
830 render_area_extent,
831 layer_count,
832 view_mask,
833 ref color_attachments,
834 ref depth_attachment,
835 ref stencil_attachment,
836 contents,
837 _ne: _,
838 } = rendering_info;
839
840 // VUID-VkRenderingInfo-flags-parameter
841 contents.validate_device(device)?;
842
843 // VUID-vkCmdBeginRendering-commandBuffer-06068
844 if self.inheritance_info.is_some() && contents == SubpassContents::SecondaryCommandBuffers {
845 return Err(RenderPassError::ContentsForbiddenInSecondaryCommandBuffer);
846 }
847
848 // No VUID, but for sanity it makes sense to treat this the same as in framebuffers.
849 if view_mask != 0 && layer_count != 1 {
850 return Err(RenderPassError::MultiviewLayersInvalid);
851 }
852
853 // VUID-VkRenderingInfo-multiview-06127
854 if view_mask != 0 && !device.enabled_features().multiview {
855 return Err(RenderPassError::RequirementNotMet {
856 required_for: "`rendering_info.viewmask` is not `0`",
857 requires_one_of: RequiresOneOf {
858 features: &["multiview"],
859 ..Default::default()
860 },
861 });
862 }
863
864 let view_count = u32::BITS - view_mask.leading_zeros();
865
866 // VUID-VkRenderingInfo-viewMask-06128
867 if view_count > properties.max_multiview_view_count.unwrap_or(0) {
868 return Err(RenderPassError::MaxMultiviewViewCountExceeded {
869 view_count,
870 max: properties.max_multiview_view_count.unwrap_or(0),
871 });
872 }
873
874 let mut samples = None;
875
876 // VUID-VkRenderingInfo-colorAttachmentCount-06106
877 if color_attachments.len() > properties.max_color_attachments as usize {
878 return Err(RenderPassError::MaxColorAttachmentsExceeded {
879 color_attachment_count: color_attachments.len() as u32,
880 max: properties.max_color_attachments,
881 });
882 }
883
884 for (attachment_index, attachment_info) in
885 color_attachments
886 .iter()
887 .enumerate()
888 .filter_map(|(index, attachment_info)| {
889 attachment_info
890 .as_ref()
891 .map(|attachment_info| (index, attachment_info))
892 })
893 {
894 let attachment_index = attachment_index as u32;
895 let RenderingAttachmentInfo {
896 image_view,
897 image_layout,
898 resolve_info,
899 load_op,
900 store_op,
901 clear_value: _,
902 _ne: _,
903 } = attachment_info;
904
905 // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
906 image_layout.validate_device(device)?;
907
908 // VUID-VkRenderingAttachmentInfo-loadOp-parameter
909 load_op.validate_device(device)?;
910
911 // VUID-VkRenderingAttachmentInfo-storeOp-parameter
912 store_op.validate_device(device)?;
913
914 // VUID-VkRenderingInfo-colorAttachmentCount-06087
915 if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
916 return Err(RenderPassError::ColorAttachmentMissingUsage { attachment_index });
917 }
918
919 let image = image_view.image();
920 let image_extent = image.dimensions().width_height_depth();
921
922 for i in 0..2 {
923 // VUID-VkRenderingInfo-pNext-06079
924 // VUID-VkRenderingInfo-pNext-06080
925 if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
926 return Err(RenderPassError::RenderAreaOutOfBounds);
927 }
928 }
929
930 // VUID-VkRenderingInfo-imageView-06070
931 match samples {
932 Some(samples) if samples == image.samples() => (),
933 Some(_) => {
934 return Err(RenderPassError::ColorAttachmentSamplesMismatch {
935 attachment_index,
936 });
937 }
938 None => samples = Some(image.samples()),
939 }
940
941 // VUID-VkRenderingAttachmentInfo-imageView-06135
942 // VUID-VkRenderingAttachmentInfo-imageView-06145
943 // VUID-VkRenderingInfo-colorAttachmentCount-06090
944 // VUID-VkRenderingInfo-colorAttachmentCount-06096
945 if matches!(
946 image_layout,
947 ImageLayout::Undefined
948 | ImageLayout::ShaderReadOnlyOptimal
949 | ImageLayout::TransferSrcOptimal
950 | ImageLayout::TransferDstOptimal
951 | ImageLayout::Preinitialized
952 | ImageLayout::PresentSrc
953 | ImageLayout::DepthStencilAttachmentOptimal
954 | ImageLayout::DepthStencilReadOnlyOptimal
955 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
956 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
957 ) {
958 return Err(RenderPassError::ColorAttachmentLayoutInvalid { attachment_index });
959 }
960
961 if let Some(resolve_info) = resolve_info {
962 let &RenderingAttachmentResolveInfo {
963 mode,
964 image_view: ref resolve_image_view,
965 image_layout: resolve_image_layout,
966 } = resolve_info;
967
968 // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
969 resolve_image_layout.validate_device(device)?;
970
971 // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
972 mode.validate_device(device)?;
973
974 let resolve_image = resolve_image_view.image();
975
976 match image_view.format().unwrap().type_color() {
977 Some(
978 NumericType::SFLOAT
979 | NumericType::UFLOAT
980 | NumericType::SNORM
981 | NumericType::UNORM
982 | NumericType::SSCALED
983 | NumericType::USCALED
984 | NumericType::SRGB,
985 ) => {
986 // VUID-VkRenderingAttachmentInfo-imageView-06129
987 if mode != ResolveMode::Average {
988 return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
989 attachment_index,
990 });
991 }
992 }
993 Some(NumericType::SINT | NumericType::UINT) => {
994 // VUID-VkRenderingAttachmentInfo-imageView-06130
995 if mode != ResolveMode::SampleZero {
996 return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
997 attachment_index,
998 });
999 }
1000 }
1001 None => (),
1002 }
1003
1004 // VUID-VkRenderingAttachmentInfo-imageView-06132
1005 if image.samples() == SampleCount::Sample1 {
1006 return Err(RenderPassError::ColorAttachmentWithResolveNotMultisampled {
1007 attachment_index,
1008 });
1009 }
1010
1011 // VUID-VkRenderingAttachmentInfo-imageView-06133
1012 if resolve_image.samples() != SampleCount::Sample1 {
1013 return Err(RenderPassError::ColorAttachmentResolveMultisampled {
1014 attachment_index,
1015 });
1016 }
1017
1018 // VUID-VkRenderingAttachmentInfo-imageView-06134
1019 if image_view.format() != resolve_image_view.format() {
1020 return Err(RenderPassError::ColorAttachmentResolveFormatMismatch {
1021 attachment_index,
1022 });
1023 }
1024
1025 // VUID-VkRenderingAttachmentInfo-imageView-06136
1026 // VUID-VkRenderingAttachmentInfo-imageView-06146
1027 // VUID-VkRenderingInfo-colorAttachmentCount-06091
1028 // VUID-VkRenderingInfo-colorAttachmentCount-06097
1029 if matches!(
1030 resolve_image_layout,
1031 ImageLayout::Undefined
1032 | ImageLayout::ShaderReadOnlyOptimal
1033 | ImageLayout::TransferSrcOptimal
1034 | ImageLayout::TransferDstOptimal
1035 | ImageLayout::Preinitialized
1036 | ImageLayout::PresentSrc
1037 | ImageLayout::DepthStencilAttachmentOptimal
1038 | ImageLayout::DepthStencilReadOnlyOptimal
1039 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
1040 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
1041 ) {
1042 return Err(RenderPassError::ColorAttachmentResolveLayoutInvalid {
1043 attachment_index,
1044 });
1045 }
1046 }
1047 }
1048
1049 if let Some(attachment_info) = depth_attachment {
1050 let RenderingAttachmentInfo {
1051 image_view,
1052 image_layout,
1053 resolve_info,
1054 load_op,
1055 store_op,
1056 clear_value: _,
1057 _ne: _,
1058 } = attachment_info;
1059
1060 // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
1061 image_layout.validate_device(device)?;
1062
1063 // VUID-VkRenderingAttachmentInfo-loadOp-parameter
1064 load_op.validate_device(device)?;
1065
1066 // VUID-VkRenderingAttachmentInfo-storeOp-parameter
1067 store_op.validate_device(device)?;
1068
1069 let image_aspects = image_view.format().unwrap().aspects();
1070
1071 // VUID-VkRenderingInfo-pDepthAttachment-06547
1072 if !image_aspects.intersects(ImageAspects::DEPTH) {
1073 return Err(RenderPassError::DepthAttachmentFormatUsageNotSupported);
1074 }
1075
1076 // VUID-VkRenderingInfo-pDepthAttachment-06088
1077 if !image_view
1078 .usage()
1079 .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1080 {
1081 return Err(RenderPassError::DepthAttachmentMissingUsage);
1082 }
1083
1084 let image = image_view.image();
1085 let image_extent = image.dimensions().width_height_depth();
1086
1087 for i in 0..2 {
1088 // VUID-VkRenderingInfo-pNext-06079
1089 // VUID-VkRenderingInfo-pNext-06080
1090 if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
1091 return Err(RenderPassError::RenderAreaOutOfBounds);
1092 }
1093 }
1094
1095 // VUID-VkRenderingInfo-imageView-06070
1096 match samples {
1097 Some(samples) if samples == image.samples() => (),
1098 Some(_) => {
1099 return Err(RenderPassError::DepthAttachmentSamplesMismatch);
1100 }
1101 None => samples = Some(image.samples()),
1102 }
1103
1104 // VUID-VkRenderingAttachmentInfo-imageView-06135
1105 // VUID-VkRenderingAttachmentInfo-imageView-06145
1106 // VUID-VkRenderingInfo-pDepthAttachment-06092
1107 if matches!(
1108 image_layout,
1109 ImageLayout::Undefined
1110 | ImageLayout::ShaderReadOnlyOptimal
1111 | ImageLayout::TransferSrcOptimal
1112 | ImageLayout::TransferDstOptimal
1113 | ImageLayout::Preinitialized
1114 | ImageLayout::PresentSrc
1115 | ImageLayout::ColorAttachmentOptimal
1116 ) {
1117 return Err(RenderPassError::DepthAttachmentLayoutInvalid);
1118 }
1119
1120 if let Some(resolve_info) = resolve_info {
1121 let &RenderingAttachmentResolveInfo {
1122 mode,
1123 image_view: ref resolve_image_view,
1124 image_layout: resolve_image_layout,
1125 } = resolve_info;
1126
1127 // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
1128 resolve_image_layout.validate_device(device)?;
1129
1130 // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
1131 mode.validate_device(device)?;
1132
1133 // VUID-VkRenderingInfo-pDepthAttachment-06102
1134 if !properties
1135 .supported_depth_resolve_modes
1136 .map_or(false, |modes| modes.contains_enum(mode))
1137 {
1138 return Err(RenderPassError::DepthAttachmentResolveModeNotSupported);
1139 }
1140
1141 let resolve_image = resolve_image_view.image();
1142
1143 // VUID-VkRenderingAttachmentInfo-imageView-06132
1144 if image.samples() == SampleCount::Sample1 {
1145 return Err(RenderPassError::DepthAttachmentWithResolveNotMultisampled);
1146 }
1147
1148 // VUID-VkRenderingAttachmentInfo-imageView-06133
1149 if resolve_image.samples() != SampleCount::Sample1 {
1150 return Err(RenderPassError::DepthAttachmentResolveMultisampled);
1151 }
1152
1153 // VUID-VkRenderingAttachmentInfo-imageView-06134
1154 if image_view.format() != resolve_image_view.format() {
1155 return Err(RenderPassError::DepthAttachmentResolveFormatMismatch);
1156 }
1157
1158 // VUID-VkRenderingAttachmentInfo-imageView-06136
1159 // VUID-VkRenderingAttachmentInfo-imageView-06146
1160 // VUID-VkRenderingInfo-pDepthAttachment-06093
1161 // VUID-VkRenderingInfo-pDepthAttachment-06098
1162 if matches!(
1163 resolve_image_layout,
1164 ImageLayout::Undefined
1165 | ImageLayout::DepthStencilReadOnlyOptimal
1166 | ImageLayout::ShaderReadOnlyOptimal
1167 | ImageLayout::TransferSrcOptimal
1168 | ImageLayout::TransferDstOptimal
1169 | ImageLayout::Preinitialized
1170 | ImageLayout::PresentSrc
1171 | ImageLayout::ColorAttachmentOptimal
1172 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
1173 ) {
1174 return Err(RenderPassError::DepthAttachmentResolveLayoutInvalid);
1175 }
1176 }
1177 }
1178
1179 if let Some(attachment_info) = stencil_attachment {
1180 let RenderingAttachmentInfo {
1181 image_view,
1182 image_layout,
1183 resolve_info,
1184 load_op,
1185 store_op,
1186 clear_value: _,
1187 _ne: _,
1188 } = attachment_info;
1189
1190 // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
1191 image_layout.validate_device(device)?;
1192
1193 // VUID-VkRenderingAttachmentInfo-loadOp-parameter
1194 load_op.validate_device(device)?;
1195
1196 // VUID-VkRenderingAttachmentInfo-storeOp-parameter
1197 store_op.validate_device(device)?;
1198
1199 let image_aspects = image_view.format().unwrap().aspects();
1200
1201 // VUID-VkRenderingInfo-pStencilAttachment-06548
1202 if !image_aspects.intersects(ImageAspects::STENCIL) {
1203 return Err(RenderPassError::StencilAttachmentFormatUsageNotSupported);
1204 }
1205
1206 // VUID-VkRenderingInfo-pStencilAttachment-06089
1207 if !image_view
1208 .usage()
1209 .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1210 {
1211 return Err(RenderPassError::StencilAttachmentMissingUsage);
1212 }
1213
1214 let image = image_view.image();
1215 let image_extent = image.dimensions().width_height_depth();
1216
1217 for i in 0..2 {
1218 // VUID-VkRenderingInfo-pNext-06079
1219 // VUID-VkRenderingInfo-pNext-06080
1220 if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
1221 return Err(RenderPassError::RenderAreaOutOfBounds);
1222 }
1223 }
1224
1225 // VUID-VkRenderingInfo-imageView-06070
1226 match samples {
1227 Some(samples) if samples == image.samples() => (),
1228 Some(_) => {
1229 return Err(RenderPassError::StencilAttachmentSamplesMismatch);
1230 }
1231 None => (),
1232 }
1233
1234 // VUID-VkRenderingAttachmentInfo-imageView-06135
1235 // VUID-VkRenderingAttachmentInfo-imageView-06145
1236 // VUID-VkRenderingInfo-pStencilAttachment-06094
1237 if matches!(
1238 image_layout,
1239 ImageLayout::Undefined
1240 | ImageLayout::ShaderReadOnlyOptimal
1241 | ImageLayout::TransferSrcOptimal
1242 | ImageLayout::TransferDstOptimal
1243 | ImageLayout::Preinitialized
1244 | ImageLayout::PresentSrc
1245 | ImageLayout::ColorAttachmentOptimal
1246 ) {
1247 return Err(RenderPassError::StencilAttachmentLayoutInvalid);
1248 }
1249
1250 if let Some(resolve_info) = resolve_info {
1251 let &RenderingAttachmentResolveInfo {
1252 mode,
1253 image_view: ref resolve_image_view,
1254 image_layout: resolve_image_layout,
1255 } = resolve_info;
1256
1257 // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
1258 resolve_image_layout.validate_device(device)?;
1259
1260 // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
1261 mode.validate_device(device)?;
1262
1263 // VUID-VkRenderingInfo-pStencilAttachment-06103
1264 if !properties
1265 .supported_stencil_resolve_modes
1266 .map_or(false, |modes| modes.contains_enum(mode))
1267 {
1268 return Err(RenderPassError::StencilAttachmentResolveModeNotSupported);
1269 }
1270
1271 let resolve_image = resolve_image_view.image();
1272
1273 // VUID-VkRenderingAttachmentInfo-imageView-06132
1274 if image.samples() == SampleCount::Sample1 {
1275 return Err(RenderPassError::StencilAttachmentWithResolveNotMultisampled);
1276 }
1277
1278 // VUID-VkRenderingAttachmentInfo-imageView-06133
1279 if resolve_image.samples() != SampleCount::Sample1 {
1280 return Err(RenderPassError::StencilAttachmentResolveMultisampled);
1281 }
1282
1283 // VUID-VkRenderingAttachmentInfo-imageView-06134
1284 if image_view.format() != resolve_image_view.format() {
1285 return Err(RenderPassError::StencilAttachmentResolveFormatMismatch);
1286 }
1287
1288 // VUID-VkRenderingAttachmentInfo-imageView-06136
1289 // VUID-VkRenderingAttachmentInfo-imageView-06146
1290 // VUID-VkRenderingInfo-pStencilAttachment-06095
1291 // VUID-VkRenderingInfo-pStencilAttachment-06099
1292 if matches!(
1293 resolve_image_layout,
1294 ImageLayout::Undefined
1295 | ImageLayout::DepthStencilReadOnlyOptimal
1296 | ImageLayout::ShaderReadOnlyOptimal
1297 | ImageLayout::TransferSrcOptimal
1298 | ImageLayout::TransferDstOptimal
1299 | ImageLayout::Preinitialized
1300 | ImageLayout::PresentSrc
1301 | ImageLayout::ColorAttachmentOptimal
1302 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
1303 ) {
1304 return Err(RenderPassError::StencilAttachmentResolveLayoutInvalid);
1305 }
1306 }
1307 }
1308
1309 if let (Some(depth_attachment_info), Some(stencil_attachment_info)) =
1310 (depth_attachment, stencil_attachment)
1311 {
1312 // VUID-VkRenderingInfo-pDepthAttachment-06085
1313 if &depth_attachment_info.image_view != &stencil_attachment_info.image_view {
1314 return Err(RenderPassError::DepthStencilAttachmentImageViewMismatch);
1315 }
1316
1317 match (
1318 &depth_attachment_info.resolve_info,
1319 &stencil_attachment_info.resolve_info,
1320 ) {
1321 (None, None) => (),
1322 (None, Some(_)) | (Some(_), None) => {
1323 // VUID-VkRenderingInfo-pDepthAttachment-06104
1324 if !properties.independent_resolve_none.unwrap_or(false) {
1325 return Err(
1326 RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
1327 );
1328 }
1329 }
1330 (Some(depth_resolve_info), Some(stencil_resolve_info)) => {
1331 // VUID-VkRenderingInfo-pDepthAttachment-06105
1332 if !properties.independent_resolve.unwrap_or(false)
1333 && depth_resolve_info.mode != stencil_resolve_info.mode
1334 {
1335 return Err(
1336 RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
1337 );
1338 }
1339
1340 // VUID-VkRenderingInfo-pDepthAttachment-06086
1341 if &depth_resolve_info.image_view != &stencil_resolve_info.image_view {
1342 return Err(
1343 RenderPassError::DepthStencilAttachmentResolveImageViewMismatch,
1344 );
1345 }
1346 }
1347 }
1348 }
1349
1350 // TODO: sync check
1351
1352 Ok(())
1353 }
1354
1355 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self1356 pub unsafe fn begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self {
1357 {
1358 let &RenderingInfo {
1359 render_area_offset,
1360 render_area_extent,
1361 layer_count,
1362 view_mask,
1363 ref color_attachments,
1364 ref depth_attachment,
1365 ref stencil_attachment,
1366 contents,
1367 _ne,
1368 } = &rendering_info;
1369
1370 let map_attachment_info = |attachment_info: &Option<_>| {
1371 if let Some(attachment_info) = attachment_info {
1372 let &RenderingAttachmentInfo {
1373 ref image_view,
1374 image_layout,
1375 resolve_info: ref resolve,
1376 load_op,
1377 store_op,
1378 clear_value,
1379 _ne: _,
1380 } = attachment_info;
1381
1382 let (resolve_mode, resolve_image_view, resolve_image_layout) =
1383 if let Some(resolve) = resolve {
1384 let &RenderingAttachmentResolveInfo {
1385 mode,
1386 ref image_view,
1387 image_layout,
1388 } = resolve;
1389
1390 (mode.into(), image_view.handle(), image_layout.into())
1391 } else {
1392 (
1393 ash::vk::ResolveModeFlags::NONE,
1394 Default::default(),
1395 Default::default(),
1396 )
1397 };
1398
1399 ash::vk::RenderingAttachmentInfo {
1400 image_view: image_view.handle(),
1401 image_layout: image_layout.into(),
1402 resolve_mode,
1403 resolve_image_view,
1404 resolve_image_layout,
1405 load_op: load_op.into(),
1406 store_op: store_op.into(),
1407 clear_value: clear_value.map_or_else(Default::default, Into::into),
1408 ..Default::default()
1409 }
1410 } else {
1411 ash::vk::RenderingAttachmentInfo {
1412 image_view: ash::vk::ImageView::null(),
1413 ..Default::default()
1414 }
1415 }
1416 };
1417
1418 let color_attachments_vk: SmallVec<[_; 2]> =
1419 color_attachments.iter().map(map_attachment_info).collect();
1420 let depth_attachment_vk = map_attachment_info(depth_attachment);
1421 let stencil_attachment_vk = map_attachment_info(stencil_attachment);
1422
1423 let rendering_info_vk = ash::vk::RenderingInfo {
1424 flags: contents.into(),
1425 render_area: ash::vk::Rect2D {
1426 offset: ash::vk::Offset2D {
1427 x: render_area_offset[0] as i32,
1428 y: render_area_offset[1] as i32,
1429 },
1430 extent: ash::vk::Extent2D {
1431 width: render_area_extent[0],
1432 height: render_area_extent[1],
1433 },
1434 },
1435 layer_count,
1436 view_mask,
1437 color_attachment_count: color_attachments_vk.len() as u32,
1438 p_color_attachments: color_attachments_vk.as_ptr(),
1439 p_depth_attachment: &depth_attachment_vk,
1440 p_stencil_attachment: &stencil_attachment_vk,
1441 ..Default::default()
1442 };
1443
1444 let fns = self.device().fns();
1445
1446 if self.device().api_version() >= Version::V1_3 {
1447 (fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info_vk);
1448 } else {
1449 debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
1450 (fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(
1451 self.handle(),
1452 &rendering_info_vk,
1453 );
1454 }
1455
1456 self.builder_state.render_pass = Some(RenderPassState {
1457 contents,
1458 render_area_offset,
1459 render_area_extent,
1460
1461 rendering_info: PipelineRenderingCreateInfo::from_rendering_info(&rendering_info),
1462 attachments: Some(RenderPassStateAttachments::from_rendering_info(
1463 &rendering_info,
1464 )),
1465
1466 render_pass: BeginRenderingState {
1467 pipeline_used: false,
1468 }
1469 .into(),
1470 });
1471 }
1472
1473 let RenderingInfo {
1474 color_attachments,
1475 depth_attachment,
1476 stencil_attachment,
1477 ..
1478 } = rendering_info;
1479
1480 for attachment_info in color_attachments.into_iter().flatten() {
1481 let RenderingAttachmentInfo {
1482 image_view,
1483 image_layout: _,
1484 resolve_info,
1485 load_op: _,
1486 store_op: _,
1487 clear_value: _,
1488 _ne: _,
1489 } = attachment_info;
1490
1491 self.resources.push(Box::new(image_view));
1492
1493 if let Some(resolve_info) = resolve_info {
1494 let RenderingAttachmentResolveInfo {
1495 mode: _,
1496 image_view,
1497 image_layout: _,
1498 } = resolve_info;
1499
1500 self.resources.push(Box::new(image_view));
1501 }
1502 }
1503
1504 if let Some(attachment_info) = depth_attachment {
1505 let RenderingAttachmentInfo {
1506 image_view,
1507 image_layout: _,
1508 resolve_info,
1509 load_op: _,
1510 store_op: _,
1511 clear_value: _,
1512 _ne: _,
1513 } = attachment_info;
1514
1515 self.resources.push(Box::new(image_view));
1516
1517 if let Some(resolve_info) = resolve_info {
1518 let RenderingAttachmentResolveInfo {
1519 mode: _,
1520 image_view,
1521 image_layout: _,
1522 } = resolve_info;
1523
1524 self.resources.push(Box::new(image_view));
1525 }
1526 }
1527
1528 if let Some(attachment_info) = stencil_attachment {
1529 let RenderingAttachmentInfo {
1530 image_view,
1531 image_layout: _,
1532 resolve_info,
1533 load_op: _,
1534 store_op: _,
1535 clear_value: _,
1536 _ne: _,
1537 } = attachment_info;
1538
1539 self.resources.push(Box::new(image_view));
1540
1541 if let Some(resolve_info) = resolve_info {
1542 let RenderingAttachmentResolveInfo {
1543 mode: _,
1544 image_view,
1545 image_layout: _,
1546 } = resolve_info;
1547
1548 self.resources.push(Box::new(image_view));
1549 }
1550 }
1551
1552 self.next_command_index += 1;
1553 self
1554 }
1555
1556 /// Ends the render pass previously begun with `begin_rendering`.
1557 ///
1558 /// # Safety
1559 ///
1560 /// - Appropriate synchronization must be provided for all images
1561 /// that are accessed by the command.
1562 /// - All images that are accessed by the command must be in the expected image layout.
1563 #[inline]
end_rendering(&mut self) -> Result<&mut Self, RenderPassError>1564 pub unsafe fn end_rendering(&mut self) -> Result<&mut Self, RenderPassError> {
1565 self.validate_end_rendering()?;
1566
1567 unsafe { Ok(self.end_rendering_unchecked()) }
1568 }
1569
validate_end_rendering(&self) -> Result<(), RenderPassError>1570 fn validate_end_rendering(&self) -> Result<(), RenderPassError> {
1571 // VUID-vkCmdEndRendering-renderpass
1572 let render_pass_state = self
1573 .builder_state
1574 .render_pass
1575 .as_ref()
1576 .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
1577
1578 // VUID?
1579 if self.inheritance_info.is_some() {
1580 return Err(RenderPassError::ForbiddenWithInheritedRenderPass);
1581 }
1582
1583 // VUID-vkCmdEndRendering-None-06161
1584 // VUID-vkCmdEndRendering-commandBuffer-06162
1585 match &render_pass_state.render_pass {
1586 RenderPassStateType::BeginRenderPass(_) => {
1587 return Err(RenderPassError::ForbiddenWithBeginRenderPass)
1588 }
1589 RenderPassStateType::BeginRendering(_) => (),
1590 }
1591
1592 // VUID-vkCmdEndRendering-commandBuffer-cmdpool
1593 debug_assert!(self
1594 .queue_family_properties()
1595 .queue_flags
1596 .intersects(QueueFlags::GRAPHICS));
1597
1598 // TODO: sync check
1599
1600 Ok(())
1601 }
1602
1603 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
end_rendering_unchecked(&mut self) -> &mut Self1604 pub unsafe fn end_rendering_unchecked(&mut self) -> &mut Self {
1605 let fns = self.device().fns();
1606
1607 if self.device().api_version() >= Version::V1_3 {
1608 (fns.v1_3.cmd_end_rendering)(self.handle());
1609 } else {
1610 debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
1611 (fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle());
1612 }
1613
1614 let command_index = self.next_command_index;
1615 let command_name = "end_rendering";
1616 let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
1617
1618 record_subpass_attachments_resolve(
1619 &mut self.resources_usage_state,
1620 command_index,
1621 command_name,
1622 render_pass_state,
1623 );
1624 record_subpass_attachments_store(
1625 &mut self.resources_usage_state,
1626 command_index,
1627 command_name,
1628 render_pass_state,
1629 );
1630
1631 self.builder_state.render_pass = None;
1632
1633 self.next_command_index += 1;
1634 self
1635 }
1636
1637 /// Clears specific regions of specific attachments of the framebuffer.
1638 ///
1639 /// `attachments` specify the types of attachments and their clear values.
1640 /// `rects` specify the regions to clear.
1641 ///
1642 /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`].
1643 /// And the command must be inside render pass.
1644 ///
1645 /// If the render pass instance this is recorded in uses multiview,
1646 /// then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one.
1647 ///
1648 /// The rectangle area must be inside the render area ranges.
1649 ///
1650 /// # Safety
1651 ///
1652 /// - Appropriate synchronization must be provided for all images
1653 /// that are accessed by the command.
1654 /// - All images that are accessed by the command must be in the expected image layout.
1655 ///
1656 /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
1657 #[inline]
clear_attachments( &mut self, attachments: impl IntoIterator<Item = ClearAttachment>, rects: impl IntoIterator<Item = ClearRect>, ) -> Result<&mut Self, RenderPassError>1658 pub unsafe fn clear_attachments(
1659 &mut self,
1660 attachments: impl IntoIterator<Item = ClearAttachment>,
1661 rects: impl IntoIterator<Item = ClearRect>,
1662 ) -> Result<&mut Self, RenderPassError> {
1663 let attachments: SmallVec<[ClearAttachment; 3]> = attachments.into_iter().collect();
1664 let rects: SmallVec<[ClearRect; 4]> = rects.into_iter().collect();
1665
1666 self.validate_clear_attachments(&attachments, &rects)?;
1667
1668 unsafe { Ok(self.clear_attachments_unchecked(attachments, rects)) }
1669 }
1670
validate_clear_attachments( &self, attachments: &[ClearAttachment], rects: &[ClearRect], ) -> Result<(), RenderPassError>1671 fn validate_clear_attachments(
1672 &self,
1673 attachments: &[ClearAttachment],
1674 rects: &[ClearRect],
1675 ) -> Result<(), RenderPassError> {
1676 // VUID-vkCmdClearAttachments-renderpass
1677 let render_pass_state = self
1678 .builder_state
1679 .render_pass
1680 .as_ref()
1681 .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
1682
1683 if render_pass_state.contents != SubpassContents::Inline {
1684 return Err(RenderPassError::ForbiddenWithSubpassContents {
1685 contents: render_pass_state.contents,
1686 });
1687 }
1688
1689 //let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
1690 //let render_pass = begin_render_pass_state.subpass.render_pass();
1691 let is_multiview = render_pass_state.rendering_info.view_mask != 0;
1692 let mut layer_count = u32::MAX;
1693
1694 for &clear_attachment in attachments {
1695 match clear_attachment {
1696 ClearAttachment::Color {
1697 color_attachment,
1698 clear_value,
1699 } => {
1700 let attachment_format = *render_pass_state
1701 .rendering_info
1702 .color_attachment_formats
1703 .get(color_attachment as usize)
1704 .ok_or(RenderPassError::ColorAttachmentIndexOutOfRange {
1705 color_attachment_index: color_attachment,
1706 num_color_attachments: render_pass_state
1707 .rendering_info
1708 .color_attachment_formats
1709 .len() as u32,
1710 })?;
1711
1712 // VUID-vkCmdClearAttachments-aspectMask-02501
1713 if !attachment_format.map_or(false, |format| {
1714 matches!(
1715 (clear_value, format.type_color().unwrap()),
1716 (
1717 ClearColorValue::Float(_),
1718 NumericType::SFLOAT
1719 | NumericType::UFLOAT
1720 | NumericType::SNORM
1721 | NumericType::UNORM
1722 | NumericType::SSCALED
1723 | NumericType::USCALED
1724 | NumericType::SRGB
1725 ) | (ClearColorValue::Int(_), NumericType::SINT)
1726 | (ClearColorValue::Uint(_), NumericType::UINT)
1727 )
1728 }) {
1729 return Err(RenderPassError::ClearAttachmentNotCompatible {
1730 clear_attachment,
1731 attachment_format,
1732 });
1733 }
1734
1735 let image_view = render_pass_state
1736 .attachments
1737 .as_ref()
1738 .and_then(|attachments| {
1739 attachments.color_attachments[color_attachment as usize].as_ref()
1740 })
1741 .map(|attachment_info| &attachment_info.image_view);
1742
1743 // We only know the layer count if we have a known attachment image.
1744 if let Some(image_view) = image_view {
1745 let array_layers = &image_view.subresource_range().array_layers;
1746 layer_count = min(layer_count, array_layers.end - array_layers.start);
1747 }
1748 }
1749 ClearAttachment::Depth(_)
1750 | ClearAttachment::Stencil(_)
1751 | ClearAttachment::DepthStencil(_) => {
1752 let depth_format = render_pass_state.rendering_info.depth_attachment_format;
1753 let stencil_format = render_pass_state.rendering_info.stencil_attachment_format;
1754
1755 // VUID-vkCmdClearAttachments-aspectMask-02502
1756 if matches!(
1757 clear_attachment,
1758 ClearAttachment::Depth(_) | ClearAttachment::DepthStencil(_)
1759 ) && !depth_format.map_or(false, |format| {
1760 format.aspects().intersects(ImageAspects::DEPTH)
1761 }) {
1762 return Err(RenderPassError::ClearAttachmentNotCompatible {
1763 clear_attachment,
1764 attachment_format: None,
1765 });
1766 }
1767
1768 // VUID-vkCmdClearAttachments-aspectMask-02503
1769 if matches!(
1770 clear_attachment,
1771 ClearAttachment::Stencil(_) | ClearAttachment::DepthStencil(_)
1772 ) && !stencil_format.map_or(false, |format| {
1773 format.aspects().intersects(ImageAspects::STENCIL)
1774 }) {
1775 return Err(RenderPassError::ClearAttachmentNotCompatible {
1776 clear_attachment,
1777 attachment_format: None,
1778 });
1779 }
1780
1781 let image_view = render_pass_state
1782 .attachments
1783 .as_ref()
1784 .and_then(|attachments| attachments.depth_attachment.as_ref())
1785 .map(|attachment_info| &attachment_info.image_view);
1786
1787 // We only know the layer count if we have a known attachment image.
1788 if let Some(image_view) = image_view {
1789 let array_layers = &image_view.subresource_range().array_layers;
1790 layer_count = min(layer_count, array_layers.end - array_layers.start);
1791 }
1792 }
1793 }
1794 }
1795
1796 for (rect_index, rect) in rects.iter().enumerate() {
1797 for i in 0..2 {
1798 // VUID-vkCmdClearAttachments-rect-02682
1799 // VUID-vkCmdClearAttachments-rect-02683
1800 if rect.extent[i] == 0 {
1801 return Err(RenderPassError::RectExtentZero { rect_index });
1802 }
1803
1804 // VUID-vkCmdClearAttachments-pRects-00016
1805 // TODO: This check will always pass in secondary command buffers because of how
1806 // it's set in `with_level`.
1807 // It needs to be checked during `execute_commands` instead.
1808 if rect.offset[i] < render_pass_state.render_area_offset[i]
1809 || rect.offset[i] + rect.extent[i]
1810 > render_pass_state.render_area_offset[i]
1811 + render_pass_state.render_area_extent[i]
1812 {
1813 return Err(RenderPassError::RectOutOfBounds { rect_index });
1814 }
1815 }
1816
1817 // VUID-vkCmdClearAttachments-layerCount-01934
1818 if rect.array_layers.is_empty() {
1819 return Err(RenderPassError::RectArrayLayersEmpty { rect_index });
1820 }
1821
1822 // VUID-vkCmdClearAttachments-pRects-00017
1823 if rect.array_layers.end > layer_count {
1824 return Err(RenderPassError::RectArrayLayersOutOfBounds { rect_index });
1825 }
1826
1827 // VUID-vkCmdClearAttachments-baseArrayLayer-00018
1828 if is_multiview && rect.array_layers != (0..1) {
1829 return Err(RenderPassError::MultiviewRectArrayLayersInvalid { rect_index });
1830 }
1831 }
1832
1833 // VUID-vkCmdClearAttachments-commandBuffer-cmdpool
1834 debug_assert!(self
1835 .queue_family_properties()
1836 .queue_flags
1837 .intersects(QueueFlags::GRAPHICS));
1838
1839 // TODO: sync check
1840
1841 Ok(())
1842 }
1843
1844 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
clear_attachments_unchecked( &mut self, attachments: impl IntoIterator<Item = ClearAttachment>, rects: impl IntoIterator<Item = ClearRect>, ) -> &mut Self1845 pub unsafe fn clear_attachments_unchecked(
1846 &mut self,
1847 attachments: impl IntoIterator<Item = ClearAttachment>,
1848 rects: impl IntoIterator<Item = ClearRect>,
1849 ) -> &mut Self {
1850 let attachments_vk: SmallVec<[_; 3]> = attachments.into_iter().map(|v| v.into()).collect();
1851 let rects_vk: SmallVec<[_; 4]> = rects
1852 .into_iter()
1853 .map(|rect| ash::vk::ClearRect {
1854 rect: ash::vk::Rect2D {
1855 offset: ash::vk::Offset2D {
1856 x: rect.offset[0] as i32,
1857 y: rect.offset[1] as i32,
1858 },
1859 extent: ash::vk::Extent2D {
1860 width: rect.extent[0],
1861 height: rect.extent[1],
1862 },
1863 },
1864 base_array_layer: rect.array_layers.start,
1865 layer_count: rect.array_layers.end - rect.array_layers.start,
1866 })
1867 .collect();
1868
1869 if attachments_vk.is_empty() || rects_vk.is_empty() {
1870 return self;
1871 }
1872
1873 let fns = self.device().fns();
1874 (fns.v1_0.cmd_clear_attachments)(
1875 self.handle(),
1876 attachments_vk.len() as u32,
1877 attachments_vk.as_ptr(),
1878 rects_vk.len() as u32,
1879 rects_vk.as_ptr(),
1880 );
1881
1882 // TODO: sync state update
1883
1884 self.next_command_index += 1;
1885 self
1886 }
1887 }
1888
record_subpass_attachments_resolve( resources_usage_state: &mut ResourcesState, command_index: usize, command_name: &'static str, render_pass_state: &RenderPassState, )1889 fn record_subpass_attachments_resolve(
1890 resources_usage_state: &mut ResourcesState,
1891 command_index: usize,
1892 command_name: &'static str,
1893 render_pass_state: &RenderPassState,
1894 ) {
1895 let attachments = render_pass_state.attachments.as_ref().unwrap();
1896
1897 let record_attachment = |resources_usage_state: &mut ResourcesState,
1898 attachment_info,
1899 aspects_override,
1900 resource_in_command,
1901 resolve_resource_in_command| {
1902 let &RenderPassStateAttachmentInfo {
1903 ref image_view,
1904 image_layout,
1905 ref resolve_info,
1906 ..
1907 } = attachment_info;
1908
1909 let image = image_view.image();
1910 let image_inner = image.inner();
1911 let mut subresource_range = image_view.subresource_range().clone();
1912 subresource_range.array_layers.start += image_inner.first_layer;
1913 subresource_range.array_layers.end += image_inner.first_layer;
1914 subresource_range.mip_levels.start += image_inner.first_mipmap_level;
1915 subresource_range.mip_levels.end += image_inner.first_mipmap_level;
1916
1917 if let Some(aspects) = aspects_override {
1918 subresource_range.aspects = aspects;
1919 }
1920
1921 let use_ref = ResourceUseRef {
1922 command_index,
1923 command_name,
1924 resource_in_command,
1925 secondary_use_ref: None,
1926 };
1927
1928 if let Some(resolve_info) = resolve_info {
1929 let &RenderPassStateAttachmentResolveInfo {
1930 image_view: ref resolve_image_view,
1931 image_layout: resolve_image_layout,
1932 ..
1933 } = resolve_info;
1934
1935 let resolve_image = resolve_image_view.image();
1936 let resolve_image_inner = resolve_image.inner();
1937 let mut resolve_subresource_range = resolve_image_view.subresource_range().clone();
1938 resolve_subresource_range.array_layers.start += resolve_image_inner.first_layer;
1939 resolve_subresource_range.array_layers.end += resolve_image_inner.first_layer;
1940 resolve_subresource_range.mip_levels.start += resolve_image_inner.first_mipmap_level;
1941 resolve_subresource_range.mip_levels.end += resolve_image_inner.first_mipmap_level;
1942
1943 if let Some(aspects) = aspects_override {
1944 resolve_subresource_range.aspects = aspects;
1945 }
1946
1947 let resolve_use_ref = ResourceUseRef {
1948 command_index,
1949 command_name,
1950 resource_in_command: resolve_resource_in_command,
1951 secondary_use_ref: None,
1952 };
1953
1954 // The resolve operation uses the stages/access for color attachments,
1955 // even for depth/stencil attachments.
1956 resources_usage_state.record_image_access(
1957 &use_ref,
1958 image_inner.image,
1959 subresource_range,
1960 PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead,
1961 image_layout,
1962 );
1963 resources_usage_state.record_image_access(
1964 &resolve_use_ref,
1965 resolve_image_inner.image,
1966 resolve_subresource_range,
1967 PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite,
1968 resolve_image_layout,
1969 );
1970 }
1971 };
1972
1973 if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
1974 record_attachment(
1975 resources_usage_state,
1976 attachment_info,
1977 Some(ImageAspects::DEPTH),
1978 ResourceInCommand::DepthStencilAttachment,
1979 ResourceInCommand::DepthStencilResolveAttachment,
1980 );
1981 }
1982
1983 if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
1984 record_attachment(
1985 resources_usage_state,
1986 attachment_info,
1987 Some(ImageAspects::STENCIL),
1988 ResourceInCommand::DepthStencilAttachment,
1989 ResourceInCommand::DepthStencilResolveAttachment,
1990 );
1991 }
1992
1993 for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
1994 .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
1995 {
1996 record_attachment(
1997 resources_usage_state,
1998 attachment_info,
1999 None,
2000 ResourceInCommand::ColorAttachment { index },
2001 ResourceInCommand::ColorResolveAttachment { index },
2002 );
2003 }
2004 }
2005
record_subpass_attachments_store( resources_usage_state: &mut ResourcesState, command_index: usize, command_name: &'static str, render_pass_state: &RenderPassState, )2006 fn record_subpass_attachments_store(
2007 resources_usage_state: &mut ResourcesState,
2008 command_index: usize,
2009 command_name: &'static str,
2010 render_pass_state: &RenderPassState,
2011 ) {
2012 let attachments = render_pass_state.attachments.as_ref().unwrap();
2013
2014 let record_attachment = |resources_usage_state: &mut ResourcesState,
2015 attachment_info,
2016 aspects_override,
2017 resource_in_command,
2018 resolve_resource_in_command| {
2019 let &RenderPassStateAttachmentInfo {
2020 ref image_view,
2021 image_layout,
2022 store_access,
2023 ref resolve_info,
2024 ..
2025 } = attachment_info;
2026
2027 if let Some(access) = store_access {
2028 let image = image_view.image();
2029 let image_inner = image.inner();
2030 let mut subresource_range = image_view.subresource_range().clone();
2031 subresource_range.array_layers.start += image_inner.first_layer;
2032 subresource_range.array_layers.end += image_inner.first_layer;
2033 subresource_range.mip_levels.start += image_inner.first_mipmap_level;
2034 subresource_range.mip_levels.end += image_inner.first_mipmap_level;
2035
2036 if let Some(aspects) = aspects_override {
2037 subresource_range.aspects = aspects;
2038 }
2039
2040 let use_ref = ResourceUseRef {
2041 command_index,
2042 command_name,
2043 resource_in_command,
2044 secondary_use_ref: None,
2045 };
2046
2047 resources_usage_state.record_image_access(
2048 &use_ref,
2049 image_inner.image,
2050 subresource_range,
2051 access,
2052 image_layout,
2053 );
2054 }
2055
2056 if let Some(resolve_info) = resolve_info {
2057 let &RenderPassStateAttachmentResolveInfo {
2058 ref image_view,
2059 image_layout,
2060 store_access,
2061 ..
2062 } = resolve_info;
2063
2064 if let Some(access) = store_access {
2065 let image = image_view.image();
2066 let image_inner = image.inner();
2067 let mut subresource_range = image_view.subresource_range().clone();
2068 subresource_range.array_layers.start += image_inner.first_layer;
2069 subresource_range.array_layers.end += image_inner.first_layer;
2070 subresource_range.mip_levels.start += image_inner.first_mipmap_level;
2071 subresource_range.mip_levels.end += image_inner.first_mipmap_level;
2072
2073 if let Some(aspects) = aspects_override {
2074 subresource_range.aspects = aspects;
2075 }
2076
2077 let use_ref = ResourceUseRef {
2078 command_index,
2079 command_name,
2080 resource_in_command: resolve_resource_in_command,
2081 secondary_use_ref: None,
2082 };
2083
2084 resources_usage_state.record_image_access(
2085 &use_ref,
2086 image_inner.image,
2087 subresource_range,
2088 access,
2089 image_layout,
2090 );
2091 }
2092 }
2093 };
2094
2095 if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
2096 record_attachment(
2097 resources_usage_state,
2098 attachment_info,
2099 Some(ImageAspects::DEPTH),
2100 ResourceInCommand::DepthStencilAttachment,
2101 ResourceInCommand::DepthStencilResolveAttachment,
2102 );
2103 }
2104
2105 if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
2106 record_attachment(
2107 resources_usage_state,
2108 attachment_info,
2109 Some(ImageAspects::STENCIL),
2110 ResourceInCommand::DepthStencilAttachment,
2111 ResourceInCommand::DepthStencilResolveAttachment,
2112 );
2113 }
2114
2115 for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
2116 .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
2117 {
2118 record_attachment(
2119 resources_usage_state,
2120 attachment_info,
2121 None,
2122 ResourceInCommand::ColorAttachment { index },
2123 ResourceInCommand::ColorResolveAttachment { index },
2124 );
2125 }
2126 }
2127
record_subpass_attachments_load( resources_usage_state: &mut ResourcesState, command_index: usize, command_name: &'static str, render_pass_state: &RenderPassState, )2128 fn record_subpass_attachments_load(
2129 resources_usage_state: &mut ResourcesState,
2130 command_index: usize,
2131 command_name: &'static str,
2132 render_pass_state: &RenderPassState,
2133 ) {
2134 let attachments = render_pass_state.attachments.as_ref().unwrap();
2135
2136 let record_attachment = |resources_usage_state: &mut ResourcesState,
2137 attachment_info,
2138 aspects_override,
2139 resource_in_command,
2140 resolve_resource_in_command| {
2141 let &RenderPassStateAttachmentInfo {
2142 ref image_view,
2143 image_layout,
2144 load_access,
2145 ref resolve_info,
2146 ..
2147 } = attachment_info;
2148
2149 if let Some(access) = load_access {
2150 let image = image_view.image();
2151 let image_inner = image.inner();
2152 let mut subresource_range = image_view.subresource_range().clone();
2153 subresource_range.array_layers.start += image_inner.first_layer;
2154 subresource_range.array_layers.end += image_inner.first_layer;
2155 subresource_range.mip_levels.start += image_inner.first_mipmap_level;
2156 subresource_range.mip_levels.end += image_inner.first_mipmap_level;
2157
2158 if let Some(aspects) = aspects_override {
2159 subresource_range.aspects = aspects;
2160 }
2161
2162 let use_ref = ResourceUseRef {
2163 command_index,
2164 command_name,
2165 resource_in_command,
2166 secondary_use_ref: None,
2167 };
2168
2169 resources_usage_state.record_image_access(
2170 &use_ref,
2171 image_inner.image,
2172 subresource_range,
2173 access,
2174 image_layout,
2175 );
2176 }
2177
2178 if let Some(resolve_info) = resolve_info {
2179 let &RenderPassStateAttachmentResolveInfo {
2180 ref image_view,
2181 image_layout,
2182 load_access,
2183 ..
2184 } = resolve_info;
2185
2186 if let Some(access) = load_access {
2187 let image = image_view.image();
2188 let image_inner = image.inner();
2189 let mut subresource_range = image_view.subresource_range().clone();
2190 subresource_range.array_layers.start += image_inner.first_layer;
2191 subresource_range.array_layers.end += image_inner.first_layer;
2192 subresource_range.mip_levels.start += image_inner.first_mipmap_level;
2193 subresource_range.mip_levels.end += image_inner.first_mipmap_level;
2194
2195 if let Some(aspects) = aspects_override {
2196 subresource_range.aspects = aspects;
2197 }
2198
2199 let use_ref = ResourceUseRef {
2200 command_index,
2201 command_name,
2202 resource_in_command: resolve_resource_in_command,
2203 secondary_use_ref: None,
2204 };
2205
2206 resources_usage_state.record_image_access(
2207 &use_ref,
2208 image_inner.image,
2209 subresource_range,
2210 access,
2211 image_layout,
2212 );
2213 }
2214 }
2215 };
2216
2217 if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
2218 record_attachment(
2219 resources_usage_state,
2220 attachment_info,
2221 Some(ImageAspects::DEPTH),
2222 ResourceInCommand::DepthStencilAttachment,
2223 ResourceInCommand::DepthStencilResolveAttachment,
2224 );
2225 }
2226
2227 if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
2228 record_attachment(
2229 resources_usage_state,
2230 attachment_info,
2231 Some(ImageAspects::STENCIL),
2232 ResourceInCommand::DepthStencilAttachment,
2233 ResourceInCommand::DepthStencilResolveAttachment,
2234 );
2235 }
2236
2237 for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
2238 .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
2239 {
2240 record_attachment(
2241 resources_usage_state,
2242 attachment_info,
2243 None,
2244 ResourceInCommand::ColorAttachment { index },
2245 ResourceInCommand::ColorResolveAttachment { index },
2246 );
2247 }
2248 }
2249