1use {
2 super::{
3 Area, Attachment, Binding, Bindings, ExecutionPipeline, Node, NodeIndex, Pass, RenderGraph,
4 node::SwapchainImageNode,
5 pass_ref::{Subresource, SubresourceAccess},
6 },
7 crate::{
8 driver::{
9 AttachmentInfo, AttachmentRef, CommandBuffer, CommandBufferInfo, Descriptor,
10 DescriptorInfo, DescriptorPool, DescriptorPoolInfo, DescriptorSet, DriverError,
11 FramebufferAttachmentImageInfo, FramebufferInfo, RenderPass, RenderPassInfo,
12 SubpassDependency, SubpassInfo,
13 accel_struct::AccelerationStructure,
14 buffer::Buffer,
15 format_aspect_mask,
16 graphic::{DepthStencilMode, GraphicPipeline},
17 image::{Image, ImageAccess, ImageViewInfo},
18 image_access_layout, initial_image_layout_access, is_read_access, is_write_access,
19 pipeline_stage_access_flags,
20 swapchain::SwapchainImage,
21 vk_sync::{
22 AccessType, BufferBarrier, GlobalBarrier, ImageBarrier, cmd::pipeline_barrier,
23 },
24 },
25 pool::{Lease, Pool},
26 },
27 ash::vk,
28 log::{
29 Level::{Debug, Trace},
30 debug, log_enabled, trace,
31 },
32 std::{
33 cell::RefCell,
34 collections::{BTreeMap, HashMap, VecDeque},
35 iter::repeat,
36 ops::Range,
37 },
38};
39
40#[cfg(not(debug_assertions))]
41use std::hint::unreachable_unchecked;
42
43#[derive(Default)]
44struct AccessCache {
45 accesses: Vec<bool>,
46 binding_count: usize,
47 read_count: Vec<usize>,
48 reads: Vec<usize>,
49}
50
51impl AccessCache {
52 #[profiling::function]
57 fn dependent_nodes(&self, pass_idx: usize) -> impl ExactSizeIterator<Item = usize> + '_ {
58 let pass_start = pass_idx * self.binding_count;
59 let pass_end = pass_start + self.read_count[pass_idx];
60 self.reads[pass_start..pass_end].iter().copied()
61 }
62
63 #[profiling::function]
69 fn dependent_passes(
70 &self,
71 node_idx: usize,
72 end_pass_idx: usize,
73 ) -> impl Iterator<Item = usize> + '_ {
74 self.accesses[node_idx..end_pass_idx * self.binding_count]
75 .iter()
76 .step_by(self.binding_count)
77 .enumerate()
78 .rev()
79 .filter_map(|(pass_idx, write)| write.then_some(pass_idx))
80 }
81
82 #[profiling::function]
84 fn interdependent_passes(
85 &self,
86 pass_idx: usize,
87 end_pass_idx: usize,
88 ) -> impl Iterator<Item = usize> + '_ {
89 self.dependent_nodes(pass_idx)
90 .flat_map(move |node_idx| self.dependent_passes(node_idx, end_pass_idx))
91 }
92
93 fn update(&mut self, graph: &RenderGraph, end_pass_idx: usize) {
94 self.binding_count = graph.bindings.len();
95
96 let cache_len = self.binding_count * end_pass_idx;
97
98 self.accesses.truncate(cache_len);
99 self.accesses.fill(false);
100 self.accesses.resize(cache_len, false);
101
102 self.read_count.clear();
103
104 self.reads.truncate(cache_len);
105 self.reads.fill(usize::MAX);
106 self.reads.resize(cache_len, usize::MAX);
107
108 thread_local! {
109 static NODES: RefCell<Vec<bool>> = Default::default();
110 }
111
112 NODES.with_borrow_mut(|nodes| {
113 nodes.truncate(self.binding_count);
114 nodes.fill(true);
115 nodes.resize(self.binding_count, true);
116
117 for (pass_idx, pass) in graph.passes[0..end_pass_idx].iter().enumerate() {
118 let pass_start = pass_idx * self.binding_count;
119 let mut read_count = 0;
120
121 for (&node_idx, accesses) in pass.execs.iter().flat_map(|exec| exec.accesses.iter())
122 {
123 self.accesses[pass_start + node_idx] = true;
124
125 if nodes[node_idx] && is_read_access(accesses.first().unwrap().access) {
126 self.reads[pass_start + read_count] = node_idx;
127 nodes[node_idx] = false;
128 read_count += 1;
129 }
130 }
131
132 if pass_idx + 1 < end_pass_idx {
133 nodes.fill(true);
134 }
135
136 self.read_count.push(read_count);
137 }
138 });
139 }
140}
141
142struct ImageSubresourceRangeDebug(vk::ImageSubresourceRange);
143
144impl std::fmt::Debug for ImageSubresourceRangeDebug {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 self.0.aspect_mask.fmt(f)?;
147
148 f.write_str(" array: ")?;
149
150 let array_layers = self.0.base_array_layer..self.0.base_array_layer + self.0.layer_count;
151 array_layers.fmt(f)?;
152
153 f.write_str(" mip: ")?;
154
155 let mip_levels = self.0.base_mip_level..self.0.base_mip_level + self.0.level_count;
156 mip_levels.fmt(f)
157 }
158}
159
160#[derive(Debug)]
161struct PhysicalPass {
162 descriptor_pool: Option<Lease<DescriptorPool>>,
163 exec_descriptor_sets: HashMap<usize, Vec<DescriptorSet>>,
164 render_pass: Option<Lease<RenderPass>>,
165}
166
167impl Drop for PhysicalPass {
168 fn drop(&mut self) {
169 self.exec_descriptor_sets.clear();
170 self.descriptor_pool = None;
171 }
172}
173
174#[derive(Debug)]
179pub struct Resolver {
180 pub(super) graph: RenderGraph,
181 physical_passes: Vec<PhysicalPass>,
182}
183
184impl Resolver {
185 pub(super) fn new(graph: RenderGraph) -> Self {
186 let physical_passes = Vec::with_capacity(graph.passes.len());
187
188 Self {
189 graph,
190 physical_passes,
191 }
192 }
193
194 #[profiling::function]
195 fn allow_merge_passes(lhs: &Pass, rhs: &Pass) -> bool {
196 fn first_graphic_pipeline(pass: &Pass) -> Option<&GraphicPipeline> {
197 pass.execs
198 .first()
199 .and_then(|exec| exec.pipeline.as_ref().map(ExecutionPipeline::as_graphic))
200 .flatten()
201 }
202
203 fn is_multiview(view_mask: u32) -> bool {
204 view_mask != 0
205 }
206
207 let lhs_pipeline = first_graphic_pipeline(lhs);
208 if lhs_pipeline.is_none() {
209 trace!(" {} is not graphic", lhs.name,);
210
211 return false;
212 }
213
214 let rhs_pipeline = first_graphic_pipeline(rhs);
215 if rhs_pipeline.is_none() {
216 trace!(" {} is not graphic", rhs.name,);
217
218 return false;
219 }
220
221 let lhs_pipeline = unsafe { lhs_pipeline.unwrap_unchecked() };
222 let rhs_pipeline = unsafe { rhs_pipeline.unwrap_unchecked() };
223
224 if lhs_pipeline.info.blend != rhs_pipeline.info.blend
226 || lhs_pipeline.info.cull_mode != rhs_pipeline.info.cull_mode
227 || lhs_pipeline.info.front_face != rhs_pipeline.info.front_face
228 || lhs_pipeline.info.polygon_mode != rhs_pipeline.info.polygon_mode
229 || lhs_pipeline.info.samples != rhs_pipeline.info.samples
230 {
231 trace!(" different rasterization modes",);
232
233 return false;
234 }
235
236 let rhs = rhs.execs.first();
237
238 debug_assert!(rhs.is_some());
240
241 let rhs = unsafe { rhs.unwrap_unchecked() };
242
243 let mut common_color_attachment = false;
244 let mut common_depth_attachment = false;
245
246 for lhs in lhs.execs.iter().rev() {
248 if is_multiview(lhs.view_mask) != is_multiview(rhs.view_mask) {
250 trace!(" incompatible multiview");
251
252 return false;
253 }
254
255 for (attachment_idx, lhs_attachment) in lhs
257 .color_attachments
258 .iter()
259 .chain(lhs.color_loads.iter())
260 .chain(lhs.color_stores.iter())
261 .chain(
262 lhs.color_clears
263 .iter()
264 .map(|(attachment_idx, (attachment, _))| (attachment_idx, attachment)),
265 )
266 .chain(
267 lhs.color_resolves
268 .iter()
269 .map(|(attachment_idx, (attachment, _))| (attachment_idx, attachment)),
270 )
271 {
272 let rhs_attachment = rhs
273 .color_attachments
274 .get(attachment_idx)
275 .or_else(|| rhs.color_loads.get(attachment_idx))
276 .or_else(|| rhs.color_stores.get(attachment_idx))
277 .or_else(|| {
278 rhs.color_clears
279 .get(attachment_idx)
280 .map(|(attachment, _)| attachment)
281 })
282 .or_else(|| {
283 rhs.color_resolves
284 .get(attachment_idx)
285 .map(|(attachment, _)| attachment)
286 });
287
288 if !Attachment::are_compatible(Some(*lhs_attachment), rhs_attachment.copied()) {
289 trace!(" incompatible color attachments");
290
291 return false;
292 }
293
294 common_color_attachment = true;
295 }
296
297 let lhs_depth_stencil = lhs
299 .depth_stencil_attachment
300 .or(lhs.depth_stencil_load)
301 .or(lhs.depth_stencil_store)
302 .or_else(|| lhs.depth_stencil_resolve.map(|(attachment, ..)| attachment))
303 .or_else(|| lhs.depth_stencil_clear.map(|(attachment, _)| attachment));
304
305 let rhs_depth_stencil = rhs
306 .depth_stencil_attachment
307 .or(rhs.depth_stencil_load)
308 .or(rhs.depth_stencil_store)
309 .or_else(|| rhs.depth_stencil_resolve.map(|(attachment, ..)| attachment))
310 .or_else(|| rhs.depth_stencil_clear.map(|(attachment, _)| attachment));
311
312 if !Attachment::are_compatible(lhs_depth_stencil, rhs_depth_stencil) {
313 trace!(" incompatible depth/stencil attachments");
314
315 return false;
316 }
317
318 common_depth_attachment |= lhs_depth_stencil.is_some() && rhs_depth_stencil.is_some();
319 }
320
321 if common_color_attachment || common_depth_attachment {
323 trace!(" merging due to common image");
324
325 return true;
326 }
327
328 if !rhs_pipeline.input_attachments.is_empty() {
330 trace!(" merging due to subpass input");
331
332 return true;
333 }
334
335 trace!(" not merging");
336
337 false
339 }
340
341 fn attachment_layout(
343 aspect_mask: vk::ImageAspectFlags,
344 is_random_access: bool,
345 is_input: bool,
346 ) -> vk::ImageLayout {
347 if aspect_mask.contains(vk::ImageAspectFlags::COLOR) {
348 if is_input {
349 vk::ImageLayout::GENERAL
350 } else {
351 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL
352 }
353 } else if aspect_mask.contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
354 {
355 if is_random_access {
356 if is_input {
357 vk::ImageLayout::GENERAL
358 } else {
359 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
360 }
361 } else {
362 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
363 }
364 } else if aspect_mask.contains(vk::ImageAspectFlags::DEPTH) {
365 if is_random_access {
366 if is_input {
367 vk::ImageLayout::GENERAL
368 } else {
369 vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL
370 }
371 } else {
372 vk::ImageLayout::DEPTH_READ_ONLY_OPTIMAL
373 }
374 } else if aspect_mask.contains(vk::ImageAspectFlags::STENCIL) {
375 if is_random_access {
376 if is_input {
377 vk::ImageLayout::GENERAL
378 } else {
379 vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL
380 }
381 } else {
382 vk::ImageLayout::STENCIL_READ_ONLY_OPTIMAL
383 }
384 } else {
385 vk::ImageLayout::UNDEFINED
386 }
387 }
388
389 #[profiling::function]
390 fn begin_render_pass(
391 cmd_buf: &CommandBuffer,
392 bindings: &[Binding],
393 pass: &Pass,
394 physical_pass: &mut PhysicalPass,
395 render_area: Area,
396 ) -> Result<(), DriverError> {
397 trace!(" begin render pass");
398
399 let render_pass = physical_pass.render_pass.as_mut().unwrap();
400 let attachment_count = render_pass.info.attachments.len();
401
402 let mut attachments = Vec::with_capacity(attachment_count);
403 attachments.resize(
404 attachment_count,
405 FramebufferAttachmentImageInfo {
406 flags: vk::ImageCreateFlags::empty(),
407 usage: vk::ImageUsageFlags::empty(),
408 width: 0,
409 height: 0,
410 layer_count: 0,
411 view_formats: vec![],
412 },
413 );
414
415 thread_local! {
416 static CLEARS_VIEWS: RefCell<(Vec<vk::ClearValue>, Vec<vk::ImageView>)> = Default::default();
417 }
418
419 CLEARS_VIEWS.with_borrow_mut(|(clear_values, image_views)| {
420 clear_values.resize_with(attachment_count, vk::ClearValue::default);
421 image_views.resize(attachment_count, vk::ImageView::null());
422
423 for exec in &pass.execs {
424 for (attachment_idx, (attachment, clear_value)) in &exec.color_clears {
425 let attachment_image = &mut attachments[*attachment_idx as usize];
426 if let Err(idx) = attachment_image
427 .view_formats
428 .binary_search(&attachment.format)
429 {
430 clear_values[*attachment_idx as usize] = vk::ClearValue {
431 color: vk::ClearColorValue {
432 float32: clear_value.0,
433 },
434 };
435
436 let image = bindings[attachment.target].as_driver_image().unwrap();
437
438 attachment_image.flags = image.info.flags;
439 attachment_image.usage = image.info.usage;
440 attachment_image.width = image.info.width >> attachment.base_mip_level;
441 attachment_image.height = image.info.height >> attachment.base_mip_level;
442 attachment_image.layer_count = attachment.array_layer_count;
443 attachment_image.view_formats.insert(idx, attachment.format);
444
445 image_views[*attachment_idx as usize] = Image::view(
446 image,
447 ImageViewInfo {
448 array_layer_count: attachment.array_layer_count,
449 aspect_mask: attachment.aspect_mask,
450 base_array_layer: attachment.base_array_layer,
451 base_mip_level: attachment.base_mip_level,
452 fmt: attachment.format,
453 mip_level_count: attachment.mip_level_count,
454 ty: image.info.ty,
455 },
456 )?;
457 }
458 }
459
460 for (attachment_idx, attachment) in exec
461 .color_attachments
462 .iter()
463 .chain(&exec.color_loads)
464 .chain(&exec.color_stores)
465 .chain(exec.color_resolves.iter().map(
466 |(dst_attachment_idx, (attachment, _))| (dst_attachment_idx, attachment),
467 ))
468 {
469 let attachment_image = &mut attachments[*attachment_idx as usize];
470 if let Err(idx) = attachment_image
471 .view_formats
472 .binary_search(&attachment.format)
473 {
474 let image = bindings[attachment.target].as_driver_image().unwrap();
475
476 attachment_image.flags = image.info.flags;
477 attachment_image.usage = image.info.usage;
478 attachment_image.width = image.info.width >> attachment.base_mip_level;
479 attachment_image.height = image.info.height >> attachment.base_mip_level;
480 attachment_image.layer_count = attachment.array_layer_count;
481 attachment_image.view_formats.insert(idx, attachment.format);
482
483 image_views[*attachment_idx as usize] = Image::view(
484 image,
485 ImageViewInfo {
486 array_layer_count: attachment.array_layer_count,
487 aspect_mask: attachment.aspect_mask,
488 base_array_layer: attachment.base_array_layer,
489 base_mip_level: attachment.base_mip_level,
490 fmt: attachment.format,
491 mip_level_count: attachment.mip_level_count,
492 ty: image.info.ty,
493 },
494 )?;
495 }
496 }
497
498 if let Some((attachment, clear_value)) = &exec.depth_stencil_clear {
499 let attachment_idx =
500 attachments.len() - 1 - exec.depth_stencil_resolve.is_some() as usize;
501 let attachment_image = &mut attachments[attachment_idx];
502 if let Err(idx) = attachment_image
503 .view_formats
504 .binary_search(&attachment.format)
505 {
506 clear_values[attachment_idx] = vk::ClearValue {
507 depth_stencil: *clear_value,
508 };
509
510 let image = bindings[attachment.target].as_driver_image().unwrap();
511
512 attachment_image.flags = image.info.flags;
513 attachment_image.usage = image.info.usage;
514 attachment_image.width = image.info.width >> attachment.base_mip_level;
515 attachment_image.height = image.info.height >> attachment.base_mip_level;
516 attachment_image.layer_count = attachment.array_layer_count;
517 attachment_image.view_formats.insert(idx, attachment.format);
518
519 image_views[attachment_idx] = Image::view(
520 image,
521 ImageViewInfo {
522 array_layer_count: attachment.array_layer_count,
523 aspect_mask: attachment.aspect_mask,
524 base_array_layer: attachment.base_array_layer,
525 base_mip_level: attachment.base_mip_level,
526 fmt: attachment.format,
527 mip_level_count: attachment.mip_level_count,
528 ty: image.info.ty,
529 },
530 )?;
531 }
532 }
533
534 if let Some(attachment) = exec
535 .depth_stencil_attachment
536 .or(exec.depth_stencil_load)
537 .or(exec.depth_stencil_store)
538 {
539 let attachment_idx =
540 attachments.len() - 1 - exec.depth_stencil_resolve.is_some() as usize;
541 let attachment_image = &mut attachments[attachment_idx];
542 if let Err(idx) = attachment_image
543 .view_formats
544 .binary_search(&attachment.format)
545 {
546 let image = bindings[attachment.target].as_driver_image().unwrap();
547
548 attachment_image.flags = image.info.flags;
549 attachment_image.usage = image.info.usage;
550 attachment_image.width = image.info.width >> attachment.base_mip_level;
551 attachment_image.height = image.info.height >> attachment.base_mip_level;
552 attachment_image.layer_count = attachment.array_layer_count;
553 attachment_image.view_formats.insert(idx, attachment.format);
554
555 image_views[attachment_idx] = Image::view(
556 image,
557 ImageViewInfo {
558 array_layer_count: attachment.array_layer_count,
559 aspect_mask: attachment.aspect_mask,
560 base_array_layer: attachment.base_array_layer,
561 base_mip_level: attachment.base_mip_level,
562 fmt: attachment.format,
563 mip_level_count: attachment.mip_level_count,
564 ty: image.info.ty,
565 },
566 )?;
567 }
568 }
569
570 if let Some(attachment) = exec
571 .depth_stencil_resolve
572 .map(|(attachment, ..)| attachment)
573 {
574 let attachment_idx = attachments.len() - 1;
575 let attachment_image = &mut attachments[attachment_idx];
576 if let Err(idx) = attachment_image
577 .view_formats
578 .binary_search(&attachment.format)
579 {
580 let image = bindings[attachment.target].as_driver_image().unwrap();
581
582 attachment_image.flags = image.info.flags;
583 attachment_image.usage = image.info.usage;
584 attachment_image.width = image.info.width >> attachment.base_mip_level;
585 attachment_image.height = image.info.height >> attachment.base_mip_level;
586 attachment_image.layer_count = attachment.array_layer_count;
587 attachment_image.view_formats.insert(idx, attachment.format);
588
589 image_views[attachment_idx] = Image::view(
590 image,
591 ImageViewInfo {
592 array_layer_count: attachment.array_layer_count,
593 aspect_mask: attachment.aspect_mask,
594 base_array_layer: attachment.base_array_layer,
595 base_mip_level: attachment.base_mip_level,
596 fmt: attachment.format,
597 mip_level_count: attachment.mip_level_count,
598 ty: image.info.ty,
599 },
600 )?;
601 }
602 }
603 }
604
605 let framebuffer =
606 RenderPass::framebuffer(render_pass, FramebufferInfo { attachments })?;
607
608 unsafe {
609 cmd_buf.device.cmd_begin_render_pass(
610 **cmd_buf,
611 &vk::RenderPassBeginInfo::default()
612 .render_pass(***render_pass)
613 .framebuffer(framebuffer)
614 .render_area(vk::Rect2D {
615 offset: vk::Offset2D {
616 x: render_area.x,
617 y: render_area.y,
618 },
619 extent: vk::Extent2D {
620 width: render_area.width,
621 height: render_area.height,
622 },
623 })
624 .clear_values(clear_values)
625 .push_next(
626 &mut vk::RenderPassAttachmentBeginInfoKHR::default()
627 .attachments(image_views),
628 ),
629 vk::SubpassContents::INLINE,
630 );
631 }
632
633 Ok(())
634 })
635 }
636
637 #[profiling::function]
638 fn bind_descriptor_sets(
639 cmd_buf: &CommandBuffer,
640 pipeline: &ExecutionPipeline,
641 physical_pass: &PhysicalPass,
642 exec_idx: usize,
643 ) {
644 if let Some(exec_descriptor_sets) = physical_pass.exec_descriptor_sets.get(&exec_idx) {
645 thread_local! {
646 static DESCRIPTOR_SETS: RefCell<Vec<vk::DescriptorSet>> = Default::default();
647 }
648
649 if exec_descriptor_sets.is_empty() {
650 return;
651 }
652
653 DESCRIPTOR_SETS.with_borrow_mut(|descriptor_sets| {
654 descriptor_sets.clear();
655 descriptor_sets.extend(
656 exec_descriptor_sets
657 .iter()
658 .map(|descriptor_set| **descriptor_set),
659 );
660
661 trace!(" bind descriptor sets {:?}", descriptor_sets);
662
663 unsafe {
664 cmd_buf.device.cmd_bind_descriptor_sets(
665 **cmd_buf,
666 pipeline.bind_point(),
667 pipeline.layout(),
668 0,
669 descriptor_sets,
670 &[],
671 );
672 }
673 });
674 }
675 }
676
677 #[profiling::function]
678 fn bind_pipeline(
679 cmd_buf: &mut CommandBuffer,
680 physical_pass: &mut PhysicalPass,
681 exec_idx: usize,
682 pipeline: &mut ExecutionPipeline,
683 depth_stencil: Option<DepthStencilMode>,
684 ) -> Result<(), DriverError> {
685 if log_enabled!(Trace) {
686 let (ty, name, vk_pipeline) = match pipeline {
687 ExecutionPipeline::Compute(pipeline) => {
688 ("compute", pipeline.name.as_ref(), ***pipeline)
689 }
690 ExecutionPipeline::Graphic(pipeline) => {
691 ("graphic", pipeline.name.as_ref(), vk::Pipeline::null())
692 }
693 ExecutionPipeline::RayTrace(pipeline) => {
694 ("ray trace", pipeline.name.as_ref(), ***pipeline)
695 }
696 };
697 if let Some(name) = name {
698 trace!(" bind {} pipeline {} ({:?})", ty, name, vk_pipeline);
699 } else {
700 trace!(" bind {} pipeline {:?}", ty, vk_pipeline);
701 }
702 }
703
704 let pipeline_bind_point = pipeline.bind_point();
706 let pipeline = match pipeline {
707 ExecutionPipeline::Compute(pipeline) => ***pipeline,
708 ExecutionPipeline::Graphic(pipeline) => RenderPass::graphic_pipeline(
709 physical_pass.render_pass.as_mut().unwrap(),
710 pipeline,
711 depth_stencil,
712 exec_idx as _,
713 )?,
714 ExecutionPipeline::RayTrace(pipeline) => ***pipeline,
715 };
716
717 unsafe {
718 cmd_buf
719 .device
720 .cmd_bind_pipeline(**cmd_buf, pipeline_bind_point, pipeline);
721 }
722
723 Ok(())
724 }
725
726 fn end_render_pass(&mut self, cmd_buf: &CommandBuffer) {
727 trace!(" end render pass");
728
729 unsafe {
730 cmd_buf.device.cmd_end_render_pass(**cmd_buf);
731 }
732 }
733
734 pub fn is_resolved(&self) -> bool {
740 self.graph.passes.is_empty()
741 }
742
743 #[allow(clippy::type_complexity)]
744 #[profiling::function]
745 fn lease_descriptor_pool<P>(
746 pool: &mut P,
747 pass: &Pass,
748 ) -> Result<Option<Lease<DescriptorPool>>, DriverError>
749 where
750 P: Pool<DescriptorPoolInfo, DescriptorPool>,
751 {
752 let max_set_idx = pass
753 .execs
754 .iter()
755 .flat_map(|exec| exec.bindings.keys())
756 .map(|descriptor| descriptor.set())
757 .max()
758 .unwrap_or_default();
759 let max_sets = pass.execs.len() as u32 * (max_set_idx + 1);
760 let mut info = DescriptorPoolInfo {
761 max_sets,
762 ..Default::default()
763 };
764
765 for pool_sizes in pass.descriptor_pools_sizes() {
767 for pool_size in pool_sizes.values() {
768 for (&descriptor_ty, &descriptor_count) in pool_size {
769 debug_assert_ne!(descriptor_count, 0);
770
771 match descriptor_ty {
772 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR => {
773 info.acceleration_structure_count += descriptor_count;
774 }
775 vk::DescriptorType::COMBINED_IMAGE_SAMPLER => {
776 info.combined_image_sampler_count += descriptor_count;
777 }
778 vk::DescriptorType::INPUT_ATTACHMENT => {
779 info.input_attachment_count += descriptor_count;
780 }
781 vk::DescriptorType::SAMPLED_IMAGE => {
782 info.sampled_image_count += descriptor_count;
783 }
784 vk::DescriptorType::SAMPLER => {
785 info.sampler_count += descriptor_count;
786 }
787 vk::DescriptorType::STORAGE_BUFFER => {
788 info.storage_buffer_count += descriptor_count;
789 }
790 vk::DescriptorType::STORAGE_BUFFER_DYNAMIC => {
791 info.storage_buffer_dynamic_count += descriptor_count;
792 }
793 vk::DescriptorType::STORAGE_IMAGE => {
794 info.storage_image_count += descriptor_count;
795 }
796 vk::DescriptorType::STORAGE_TEXEL_BUFFER => {
797 info.storage_texel_buffer_count += descriptor_count;
798 }
799 vk::DescriptorType::UNIFORM_BUFFER => {
800 info.uniform_buffer_count += descriptor_count;
801 }
802 vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC => {
803 info.uniform_buffer_dynamic_count += descriptor_count;
804 }
805 vk::DescriptorType::UNIFORM_TEXEL_BUFFER => {
806 info.uniform_texel_buffer_count += descriptor_count;
807 }
808 _ => unimplemented!("{descriptor_ty:?}"),
809 };
810 }
811 }
812 }
813
814 if info.is_empty() {
816 return Ok(None);
817 }
818
819 const ATOM: u32 = 1 << 5;
821 info.acceleration_structure_count =
822 info.acceleration_structure_count.next_multiple_of(ATOM);
823 info.combined_image_sampler_count =
824 info.combined_image_sampler_count.next_multiple_of(ATOM);
825 info.input_attachment_count = info.input_attachment_count.next_multiple_of(ATOM);
826 info.sampled_image_count = info.sampled_image_count.next_multiple_of(ATOM);
827 info.sampler_count = info.sampler_count.next_multiple_of(ATOM);
828 info.storage_buffer_count = info.storage_buffer_count.next_multiple_of(ATOM);
829 info.storage_buffer_dynamic_count =
830 info.storage_buffer_dynamic_count.next_multiple_of(ATOM);
831 info.storage_image_count = info.storage_image_count.next_multiple_of(ATOM);
832 info.storage_texel_buffer_count = info.storage_texel_buffer_count.next_multiple_of(ATOM);
833 info.uniform_buffer_count = info.uniform_buffer_count.next_multiple_of(ATOM);
834 info.uniform_buffer_dynamic_count =
835 info.uniform_buffer_dynamic_count.next_multiple_of(ATOM);
836 info.uniform_texel_buffer_count = info.uniform_texel_buffer_count.next_multiple_of(ATOM);
837
838 Ok(Some(pool.lease(info)?))
843 }
844
845 #[profiling::function]
846 fn lease_render_pass<P>(
847 &self,
848 pool: &mut P,
849 pass_idx: usize,
850 ) -> Result<Lease<RenderPass>, DriverError>
851 where
852 P: Pool<RenderPassInfo, RenderPass>,
853 {
854 let pass = &self.graph.passes[pass_idx];
855 let (mut color_attachment_count, mut depth_stencil_attachment_count) = (0, 0);
856 for exec in &pass.execs {
857 color_attachment_count = color_attachment_count
858 .max(
859 exec.color_attachments
860 .keys()
861 .max()
862 .map(|attachment_idx| attachment_idx + 1)
863 .unwrap_or_default() as usize,
864 )
865 .max(
866 exec.color_clears
867 .keys()
868 .max()
869 .map(|attachment_idx| attachment_idx + 1)
870 .unwrap_or_default() as usize,
871 )
872 .max(
873 exec.color_loads
874 .keys()
875 .max()
876 .map(|attachment_idx| attachment_idx + 1)
877 .unwrap_or_default() as usize,
878 )
879 .max(
880 exec.color_resolves
881 .keys()
882 .max()
883 .map(|attachment_idx| attachment_idx + 1)
884 .unwrap_or_default() as usize,
885 )
886 .max(
887 exec.color_stores
888 .keys()
889 .max()
890 .map(|attachment_idx| attachment_idx + 1)
891 .unwrap_or_default() as usize,
892 );
893 let has_depth_stencil_attachment = exec.depth_stencil_attachment.is_some()
894 || exec.depth_stencil_clear.is_some()
895 || exec.depth_stencil_load.is_some()
896 || exec.depth_stencil_store.is_some();
897 let has_depth_stencil_resolve = exec.depth_stencil_resolve.is_some();
898
899 depth_stencil_attachment_count = depth_stencil_attachment_count
900 .max(has_depth_stencil_attachment as usize + has_depth_stencil_resolve as usize);
901 }
902
903 let attachment_count = color_attachment_count + depth_stencil_attachment_count;
904 let mut attachments = Vec::with_capacity(attachment_count);
905 attachments.resize_with(attachment_count, AttachmentInfo::default);
906
907 let mut subpasses = Vec::<SubpassInfo>::with_capacity(pass.execs.len());
908
909 {
910 let mut color_set = vec![false; attachment_count];
911 let mut depth_stencil_set = false;
912
913 for exec in &pass.execs {
915 for (attachment_idx, (cleared_attachment, _)) in &exec.color_clears {
917 let color_set = &mut color_set[*attachment_idx as usize];
918 if *color_set {
919 continue;
920 }
921
922 let attachment = &mut attachments[*attachment_idx as usize];
923 attachment.fmt = cleared_attachment.format;
924 attachment.sample_count = cleared_attachment.sample_count;
925 attachment.load_op = vk::AttachmentLoadOp::CLEAR;
926 attachment.initial_layout = vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL;
927 *color_set = true;
928 }
929
930 for (attachment_idx, loaded_attachment) in &exec.color_loads {
932 let color_set = &mut color_set[*attachment_idx as usize];
933 if *color_set {
934 continue;
935 }
936
937 let attachment = &mut attachments[*attachment_idx as usize];
938 attachment.fmt = loaded_attachment.format;
939 attachment.sample_count = loaded_attachment.sample_count;
940 attachment.load_op = vk::AttachmentLoadOp::LOAD;
941 attachment.initial_layout = vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL;
942 *color_set = true;
943 }
944
945 if !depth_stencil_set {
947 if let Some((cleared_attachment, _)) = exec.depth_stencil_clear {
948 let attachment = &mut attachments[color_attachment_count];
949 attachment.fmt = cleared_attachment.format;
950 attachment.sample_count = cleared_attachment.sample_count;
951 attachment.initial_layout = if cleared_attachment
952 .aspect_mask
953 .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
954 {
955 attachment.load_op = vk::AttachmentLoadOp::CLEAR;
956 attachment.stencil_load_op = vk::AttachmentLoadOp::CLEAR;
957
958 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
959 } else if cleared_attachment
960 .aspect_mask
961 .contains(vk::ImageAspectFlags::DEPTH)
962 {
963 attachment.load_op = vk::AttachmentLoadOp::CLEAR;
964
965 vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL
966 } else {
967 attachment.stencil_load_op = vk::AttachmentLoadOp::CLEAR;
968
969 vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL
970 };
971 depth_stencil_set = true;
972 } else if let Some(loaded_attachment) = exec.depth_stencil_load {
973 let attachment = &mut attachments[color_attachment_count];
975 attachment.fmt = loaded_attachment.format;
976 attachment.sample_count = loaded_attachment.sample_count;
977 attachment.initial_layout = if loaded_attachment
978 .aspect_mask
979 .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
980 {
981 attachment.load_op = vk::AttachmentLoadOp::LOAD;
982 attachment.stencil_load_op = vk::AttachmentLoadOp::LOAD;
983
984 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
985 } else if loaded_attachment
986 .aspect_mask
987 .contains(vk::ImageAspectFlags::DEPTH)
988 {
989 attachment.load_op = vk::AttachmentLoadOp::LOAD;
990
991 vk::ImageLayout::DEPTH_READ_ONLY_OPTIMAL
992 } else {
993 attachment.stencil_load_op = vk::AttachmentLoadOp::LOAD;
994
995 vk::ImageLayout::STENCIL_READ_ONLY_OPTIMAL
996 };
997 depth_stencil_set = true;
998 } else if exec.depth_stencil_clear.is_some()
999 || exec.depth_stencil_store.is_some()
1000 {
1001 depth_stencil_set = true;
1002 }
1003 }
1004 }
1005 }
1006
1007 {
1008 let mut color_set = vec![false; attachment_count];
1009 let mut depth_stencil_set = false;
1010 let mut depth_stencil_resolve_set = false;
1011
1012 for exec in pass.execs.iter().rev() {
1014 for (attachment_idx, (resolved_attachment, _)) in &exec.color_resolves {
1016 let color_set = &mut color_set[*attachment_idx as usize];
1017 if *color_set {
1018 continue;
1019 }
1020
1021 let attachment = &mut attachments[*attachment_idx as usize];
1022 attachment.fmt = resolved_attachment.format;
1023 attachment.sample_count = resolved_attachment.sample_count;
1024 attachment.final_layout = vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL;
1025 *color_set = true;
1026 }
1027
1028 for (attachment_idx, stored_attachment) in &exec.color_stores {
1030 let color_set = &mut color_set[*attachment_idx as usize];
1031 if *color_set {
1032 continue;
1033 }
1034
1035 let attachment = &mut attachments[*attachment_idx as usize];
1036 attachment.fmt = stored_attachment.format;
1037 attachment.sample_count = stored_attachment.sample_count;
1038 attachment.store_op = vk::AttachmentStoreOp::STORE;
1039 attachment.final_layout = vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL;
1040 *color_set = true;
1041 }
1042
1043 if !depth_stencil_set {
1045 if let Some(stored_attachment) = exec.depth_stencil_store {
1046 let attachment = &mut attachments[color_attachment_count];
1047 attachment.fmt = stored_attachment.format;
1048 attachment.sample_count = stored_attachment.sample_count;
1049 attachment.final_layout = if stored_attachment
1050 .aspect_mask
1051 .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
1052 {
1053 attachment.store_op = vk::AttachmentStoreOp::STORE;
1054 attachment.stencil_store_op = vk::AttachmentStoreOp::STORE;
1055
1056 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
1057 } else if stored_attachment
1058 .aspect_mask
1059 .contains(vk::ImageAspectFlags::DEPTH)
1060 {
1061 attachment.store_op = vk::AttachmentStoreOp::STORE;
1062
1063 vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL
1064 } else {
1065 attachment.stencil_store_op = vk::AttachmentStoreOp::STORE;
1066
1067 vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL
1068 };
1069 depth_stencil_set = true;
1070 }
1071 }
1072
1073 if !depth_stencil_resolve_set {
1075 if let Some((resolved_attachment, ..)) = exec.depth_stencil_resolve {
1076 let attachment = attachments.last_mut().unwrap();
1077 attachment.fmt = resolved_attachment.format;
1078 attachment.sample_count = resolved_attachment.sample_count;
1079 attachment.final_layout = if resolved_attachment
1080 .aspect_mask
1081 .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
1082 {
1083 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
1084 } else if resolved_attachment
1085 .aspect_mask
1086 .contains(vk::ImageAspectFlags::DEPTH)
1087 {
1088 vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL
1089 } else {
1090 vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL
1091 };
1092 depth_stencil_resolve_set = true;
1093 }
1094 }
1095 }
1096 }
1097
1098 for attachment in &mut attachments {
1099 if attachment.load_op == vk::AttachmentLoadOp::DONT_CARE {
1100 attachment.initial_layout = attachment.final_layout;
1101 } else if attachment.store_op == vk::AttachmentStoreOp::DONT_CARE
1102 && attachment.stencil_store_op == vk::AttachmentStoreOp::DONT_CARE
1103 {
1104 attachment.final_layout = attachment.initial_layout;
1105 }
1106 }
1107
1108 for (exec_idx, exec) in pass.execs.iter().enumerate() {
1110 let pipeline = exec
1111 .pipeline
1112 .as_ref()
1113 .map(|pipeline| pipeline.unwrap_graphic())
1114 .unwrap();
1115 let mut subpass_info = SubpassInfo::with_capacity(attachment_count);
1116
1117 for attachment_idx in pipeline.input_attachments.iter() {
1119 debug_assert!(
1120 !exec.color_clears.contains_key(attachment_idx),
1121 "cannot clear color attachment index {attachment_idx} because it uses subpass input",
1122 );
1123
1124 let exec_attachment = exec
1125 .color_attachments
1126 .get(attachment_idx)
1127 .or_else(|| exec.color_loads.get(attachment_idx))
1128 .or_else(|| exec.color_stores.get(attachment_idx))
1129 .expect("subpass input attachment index not attached, loaded, or stored");
1130 let is_random_access = exec.color_stores.contains_key(attachment_idx);
1131 subpass_info.input_attachments.push(AttachmentRef {
1132 attachment: *attachment_idx,
1133 aspect_mask: exec_attachment.aspect_mask,
1134 layout: Self::attachment_layout(
1135 exec_attachment.aspect_mask,
1136 is_random_access,
1137 true,
1138 ),
1139 });
1140
1141 for prev_exec_idx in (0..exec_idx - 1).rev() {
1145 let prev_exec = &pass.execs[prev_exec_idx];
1146 if prev_exec.color_stores.contains_key(attachment_idx) {
1147 break;
1148 }
1149
1150 let prev_subpass = &mut subpasses[prev_exec_idx];
1151 prev_subpass.preserve_attachments.push(*attachment_idx);
1152 }
1153 }
1154
1155 for attachment_idx in 0..color_attachment_count as u32 {
1157 let is_input = subpass_info
1158 .input_attachments
1159 .iter()
1160 .any(|input| input.attachment == attachment_idx);
1161 subpass_info.color_attachments.push(AttachmentRef {
1162 attachment: vk::ATTACHMENT_UNUSED,
1163 aspect_mask: vk::ImageAspectFlags::COLOR,
1164 layout: Self::attachment_layout(vk::ImageAspectFlags::COLOR, true, is_input),
1165 });
1166 }
1167
1168 for attachment_idx in exec
1169 .color_attachments
1170 .keys()
1171 .chain(exec.color_clears.keys())
1172 .chain(exec.color_loads.keys())
1173 .chain(exec.color_stores.keys())
1174 {
1175 subpass_info.color_attachments[*attachment_idx as usize].attachment =
1176 *attachment_idx;
1177 }
1178
1179 if let Some(depth_stencil) = exec
1181 .depth_stencil_attachment
1182 .or(exec.depth_stencil_load)
1183 .or(exec.depth_stencil_store)
1184 .or_else(|| exec.depth_stencil_clear.map(|(attachment, _)| attachment))
1185 {
1186 let is_random_access = exec.depth_stencil_clear.is_some()
1187 || exec.depth_stencil_load.is_some()
1188 || exec.depth_stencil_store.is_some();
1189 subpass_info.depth_stencil_attachment = Some(AttachmentRef {
1190 attachment: color_attachment_count as u32,
1191 aspect_mask: depth_stencil.aspect_mask,
1192 layout: Self::attachment_layout(
1193 depth_stencil.aspect_mask,
1194 is_random_access,
1195 false,
1196 ),
1197 });
1198 }
1199
1200 subpass_info.color_resolve_attachments.extend(
1202 repeat(AttachmentRef {
1203 attachment: vk::ATTACHMENT_UNUSED,
1204 aspect_mask: vk::ImageAspectFlags::empty(),
1205 layout: vk::ImageLayout::UNDEFINED,
1206 })
1207 .take(color_attachment_count),
1208 );
1209
1210 for (dst_attachment_idx, (resolved_attachment, src_attachment_idx)) in
1212 &exec.color_resolves
1213 {
1214 let is_input = subpass_info
1215 .input_attachments
1216 .iter()
1217 .any(|input| input.attachment == *dst_attachment_idx);
1218 subpass_info.color_resolve_attachments[*src_attachment_idx as usize] =
1219 AttachmentRef {
1220 attachment: *dst_attachment_idx,
1221 aspect_mask: resolved_attachment.aspect_mask,
1222 layout: Self::attachment_layout(
1223 resolved_attachment.aspect_mask,
1224 true,
1225 is_input,
1226 ),
1227 };
1228 }
1229
1230 if let Some((
1231 resolved_attachment,
1232 dst_attachment_idx,
1233 depth_resolve_mode,
1234 stencil_resolve_mode,
1235 )) = exec.depth_stencil_resolve
1236 {
1237 subpass_info.depth_stencil_resolve_attachment = Some((
1238 AttachmentRef {
1239 attachment: dst_attachment_idx + 1,
1240 aspect_mask: resolved_attachment.aspect_mask,
1241 layout: Self::attachment_layout(
1242 resolved_attachment.aspect_mask,
1243 true,
1244 false,
1245 ),
1246 },
1247 depth_resolve_mode,
1248 stencil_resolve_mode,
1249 ))
1250 }
1251
1252 subpass_info.view_mask = exec.view_mask;
1253 subpass_info.correlated_view_mask = exec.correlated_view_mask;
1254
1255 subpasses.push(subpass_info);
1256 }
1257
1258 let dependencies =
1260 {
1261 let mut dependencies = BTreeMap::new();
1262 for (exec_idx, exec) in pass.execs.iter().enumerate() {
1263 'accesses: for (node_idx, accesses) in exec.accesses.iter() {
1265 let (mut curr_stages, mut curr_access) =
1266 pipeline_stage_access_flags(accesses.first().unwrap().access);
1267 if curr_stages.contains(vk::PipelineStageFlags::ALL_COMMANDS) {
1268 curr_stages |= vk::PipelineStageFlags::ALL_GRAPHICS;
1269 curr_stages &= !vk::PipelineStageFlags::ALL_COMMANDS;
1270 }
1271
1272 for (prev_exec_idx, prev_exec) in
1274 pass.execs[0..exec_idx].iter().enumerate().rev()
1275 {
1276 if let Some(accesses) = prev_exec.accesses.get(node_idx) {
1277 for &SubresourceAccess { access, .. } in accesses {
1278 let (mut prev_stages, prev_access) =
1281 pipeline_stage_access_flags(access);
1282 if prev_stages.contains(vk::PipelineStageFlags::ALL_COMMANDS) {
1283 prev_stages |= vk::PipelineStageFlags::ALL_GRAPHICS;
1284 prev_stages &= !vk::PipelineStageFlags::ALL_COMMANDS;
1285 }
1286
1287 let common_stages = curr_stages & prev_stages;
1288 if common_stages.is_empty() {
1289 continue;
1291 }
1292
1293 let dep = dependencies
1294 .entry((prev_exec_idx, exec_idx))
1295 .or_insert_with(|| {
1296 SubpassDependency::new(
1297 prev_exec_idx as _,
1298 exec_idx as _,
1299 )
1300 });
1301
1302 dep.src_stage_mask |= common_stages;
1304 dep.src_access_mask |= prev_access;
1305
1306 dep.dst_stage_mask |= curr_stages;
1308 dep.dst_access_mask |= curr_access;
1309
1310 if (prev_stages | curr_stages).intersects(
1313 vk::PipelineStageFlags::FRAGMENT_SHADER
1314 | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
1315 | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS
1316 | vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
1317 ) {
1318 dep.dependency_flags |= vk::DependencyFlags::BY_REGION;
1319 }
1320
1321 curr_stages &= !common_stages;
1322 curr_access &= !prev_access;
1323
1324 if curr_stages.is_empty() {
1327 continue 'accesses;
1328 }
1329 }
1330 }
1331 }
1332
1333 for prev_subpass in self.graph.passes[0..pass_idx]
1335 .iter()
1336 .rev()
1337 .flat_map(|pass| pass.execs.iter().rev())
1338 {
1339 if let Some(accesses) = prev_subpass.accesses.get(node_idx) {
1340 for &SubresourceAccess { access, .. } in accesses {
1341 let (prev_stages, prev_access) =
1344 pipeline_stage_access_flags(access);
1345 let common_stages = curr_stages & prev_stages;
1346 if common_stages.is_empty() {
1347 continue;
1349 }
1350
1351 let dep = dependencies
1352 .entry((vk::SUBPASS_EXTERNAL as _, exec_idx))
1353 .or_insert_with(|| {
1354 SubpassDependency::new(
1355 vk::SUBPASS_EXTERNAL as _,
1356 exec_idx as _,
1357 )
1358 });
1359
1360 dep.src_stage_mask |= common_stages;
1362 dep.src_access_mask |= prev_access;
1363
1364 dep.dst_stage_mask |=
1366 curr_stages.min(vk::PipelineStageFlags::ALL_GRAPHICS);
1367 dep.dst_access_mask |= curr_access;
1368
1369 if (prev_stages | curr_stages).intersects(
1372 vk::PipelineStageFlags::FRAGMENT_SHADER
1373 | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
1374 | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS
1375 | vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
1376 ) {
1377 dep.dependency_flags |= vk::DependencyFlags::BY_REGION;
1378 }
1379
1380 curr_stages &= !common_stages;
1381 curr_access &= !prev_access;
1382
1383 if curr_stages.is_empty() {
1386 continue 'accesses;
1387 }
1388 }
1389 }
1390 }
1391
1392 if !curr_stages.is_empty() {
1394 let dep = dependencies
1395 .entry((vk::SUBPASS_EXTERNAL as _, exec_idx))
1396 .or_insert_with(|| {
1397 SubpassDependency::new(vk::SUBPASS_EXTERNAL as _, exec_idx as _)
1398 });
1399
1400 dep.src_stage_mask |= curr_stages;
1402 dep.src_access_mask |= curr_access;
1403
1404 dep.dst_stage_mask |= vk::PipelineStageFlags::TOP_OF_PIPE;
1406 dep.dst_access_mask =
1407 vk::AccessFlags::MEMORY_READ | vk::AccessFlags::MEMORY_WRITE;
1408 }
1409 }
1410
1411 for (other_idx, other) in pass.execs[0..exec_idx].iter().enumerate() {
1414 for attachment_idx in exec.color_loads.keys() {
1416 if other.color_clears.contains_key(attachment_idx)
1418 || other.color_stores.contains_key(attachment_idx)
1419 || other.color_resolves.contains_key(attachment_idx)
1420 {
1421 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1422 || SubpassDependency::new(other_idx as _, exec_idx as _),
1423 );
1424
1425 dep.src_stage_mask |=
1427 vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT;
1428 dep.src_access_mask |= vk::AccessFlags::COLOR_ATTACHMENT_WRITE;
1429
1430 dep.dst_stage_mask |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS;
1432 dep.dst_access_mask |= vk::AccessFlags::COLOR_ATTACHMENT_READ;
1433 }
1434
1435 if other.color_loads.contains_key(attachment_idx) {
1437 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1438 || SubpassDependency::new(other_idx as _, exec_idx as _),
1439 );
1440
1441 dep.src_stage_mask |= vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
1443 dep.src_access_mask |= vk::AccessFlags::COLOR_ATTACHMENT_READ;
1444
1445 dep.dst_stage_mask |= vk::PipelineStageFlags::FRAGMENT_SHADER;
1447 dep.dst_access_mask |= vk::AccessFlags::COLOR_ATTACHMENT_READ;
1448 }
1449 }
1450
1451 if exec.depth_stencil_load.is_some() {
1453 if other.depth_stencil_clear.is_some()
1455 || other.depth_stencil_store.is_some()
1456 || other.depth_stencil_resolve.is_some()
1457 {
1458 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1459 || SubpassDependency::new(other_idx as _, exec_idx as _),
1460 );
1461
1462 dep.src_stage_mask |= vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
1464 dep.src_access_mask |=
1465 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
1466
1467 dep.dst_stage_mask |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS;
1469 dep.dst_access_mask |=
1470 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ;
1471 }
1472
1473 if other.depth_stencil_load.is_some() {
1476 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1477 || SubpassDependency::new(other_idx as _, exec_idx as _),
1478 );
1479
1480 dep.src_stage_mask |= vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
1482 dep.src_access_mask |=
1483 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ;
1484
1485 dep.dst_stage_mask |= vk::PipelineStageFlags::FRAGMENT_SHADER;
1487 dep.dst_access_mask |=
1488 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ;
1489 }
1490 }
1491
1492 for (attachment_idx, aspect_mask) in
1494 exec.color_clears
1495 .iter()
1496 .map(|(attachment_idx, (attachment, _))| {
1497 (*attachment_idx, attachment.aspect_mask)
1498 })
1499 .chain(exec.color_resolves.iter().map(
1500 |(dst_attachment_idx, (resolved_attachment, _))| {
1501 (*dst_attachment_idx, resolved_attachment.aspect_mask)
1502 },
1503 ))
1504 .chain(exec.color_stores.iter().map(
1505 |(attachment_idx, attachment)| {
1506 (*attachment_idx, attachment.aspect_mask)
1507 },
1508 ))
1509 {
1510 let stage = match aspect_mask {
1511 mask if mask.contains(vk::ImageAspectFlags::COLOR) => {
1512 vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
1513 }
1514 mask if mask.intersects(
1515 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1516 ) =>
1517 {
1518 vk::PipelineStageFlags::LATE_FRAGMENT_TESTS
1519 }
1520 _ => vk::PipelineStageFlags::ALL_GRAPHICS,
1521 };
1522
1523 if other.color_clears.contains_key(&attachment_idx)
1525 || other.color_stores.contains_key(&attachment_idx)
1526 || other.color_resolves.contains_key(&attachment_idx)
1527 {
1528 let access = match aspect_mask {
1529 mask if mask.contains(vk::ImageAspectFlags::COLOR) => {
1530 vk::AccessFlags::COLOR_ATTACHMENT_WRITE
1531 }
1532 mask if mask.intersects(
1533 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1534 ) =>
1535 {
1536 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
1537 }
1538 _ => {
1539 vk::AccessFlags::MEMORY_READ | vk::AccessFlags::MEMORY_WRITE
1540 }
1541 };
1542
1543 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1544 || SubpassDependency::new(other_idx as _, exec_idx as _),
1545 );
1546
1547 dep.src_stage_mask |= stage;
1549 dep.src_access_mask |= access;
1550
1551 dep.dst_stage_mask |= stage;
1553 dep.dst_access_mask |= access;
1554 }
1555
1556 if other.color_loads.contains_key(&attachment_idx) {
1558 let (src_access, dst_access) = match aspect_mask {
1559 mask if mask.contains(vk::ImageAspectFlags::COLOR) => (
1560 vk::AccessFlags::COLOR_ATTACHMENT_READ,
1561 vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
1562 ),
1563 mask if mask.intersects(
1564 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1565 ) =>
1566 {
1567 (
1568 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
1569 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
1570 )
1571 }
1572 _ => (
1573 vk::AccessFlags::MEMORY_READ
1574 | vk::AccessFlags::MEMORY_WRITE,
1575 vk::AccessFlags::MEMORY_READ
1576 | vk::AccessFlags::MEMORY_WRITE,
1577 ),
1578 };
1579
1580 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1581 || SubpassDependency::new(other_idx as _, exec_idx as _),
1582 );
1583
1584 dep.src_stage_mask |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS;
1586 dep.src_access_mask |= src_access;
1587
1588 dep.dst_stage_mask |= stage;
1590 dep.dst_access_mask |= dst_access;
1591 }
1592 }
1593
1594 if let Some(aspect_mask) = exec
1596 .depth_stencil_clear
1597 .map(|(attachment, _)| attachment.aspect_mask)
1598 .or_else(|| {
1599 exec.depth_stencil_store
1600 .map(|attachment| attachment.aspect_mask)
1601 })
1602 .or_else(|| {
1603 exec.depth_stencil_resolve
1604 .map(|(attachment, ..)| attachment.aspect_mask)
1605 })
1606 {
1607 let stage = match aspect_mask {
1608 mask if mask.contains(vk::ImageAspectFlags::COLOR) => {
1609 vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
1610 }
1611 mask if mask.intersects(
1612 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1613 ) =>
1614 {
1615 vk::PipelineStageFlags::LATE_FRAGMENT_TESTS
1616 }
1617 _ => vk::PipelineStageFlags::ALL_GRAPHICS,
1618 };
1619
1620 if other.depth_stencil_clear.is_some()
1622 || other.depth_stencil_store.is_some()
1623 || other.depth_stencil_resolve.is_some()
1624 {
1625 let access = match aspect_mask {
1626 mask if mask.contains(vk::ImageAspectFlags::COLOR) => {
1627 vk::AccessFlags::COLOR_ATTACHMENT_WRITE
1628 }
1629 mask if mask.intersects(
1630 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1631 ) =>
1632 {
1633 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
1634 }
1635 _ => {
1636 vk::AccessFlags::MEMORY_READ | vk::AccessFlags::MEMORY_WRITE
1637 }
1638 };
1639
1640 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1641 || SubpassDependency::new(other_idx as _, exec_idx as _),
1642 );
1643
1644 dep.src_stage_mask |= stage;
1646 dep.src_access_mask |= access;
1647
1648 dep.dst_stage_mask |= stage;
1650 dep.dst_access_mask |= access;
1651 }
1652
1653 if other.depth_stencil_load.is_some() {
1655 let (src_access, dst_access) = match aspect_mask {
1656 mask if mask.contains(vk::ImageAspectFlags::COLOR) => (
1657 vk::AccessFlags::COLOR_ATTACHMENT_READ,
1658 vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
1659 ),
1660 mask if mask.intersects(
1661 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
1662 ) =>
1663 {
1664 (
1665 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
1666 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
1667 )
1668 }
1669 _ => (
1670 vk::AccessFlags::MEMORY_READ
1671 | vk::AccessFlags::MEMORY_WRITE,
1672 vk::AccessFlags::MEMORY_READ
1673 | vk::AccessFlags::MEMORY_WRITE,
1674 ),
1675 };
1676
1677 let dep = dependencies.entry((other_idx, exec_idx)).or_insert_with(
1678 || SubpassDependency::new(other_idx as _, exec_idx as _),
1679 );
1680
1681 dep.src_stage_mask |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS;
1683 dep.src_access_mask |= src_access;
1684
1685 dep.dst_stage_mask |= stage;
1687 dep.dst_access_mask |= dst_access;
1688 }
1689 }
1690 }
1691 }
1692
1693 dependencies.into_values().collect::<Vec<_>>()
1694 };
1695
1696 pool.lease(RenderPassInfo {
1705 attachments,
1706 dependencies,
1707 subpasses,
1708 })
1709 }
1710
1711 #[profiling::function]
1712 fn lease_scheduled_resources<P>(
1713 &mut self,
1714 pool: &mut P,
1715 schedule: &[usize],
1716 ) -> Result<(), DriverError>
1717 where
1718 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
1719 {
1720 for pass_idx in schedule.iter().copied() {
1721 let pass = &mut self.graph.passes[pass_idx];
1725
1726 trace!("leasing [{pass_idx}: {}]", pass.name);
1727
1728 let descriptor_pool = Self::lease_descriptor_pool(pool, pass)?;
1729 let mut exec_descriptor_sets = HashMap::with_capacity(
1730 descriptor_pool
1731 .as_ref()
1732 .map(|descriptor_pool| descriptor_pool.info.max_sets as usize)
1733 .unwrap_or_default(),
1734 );
1735 if let Some(descriptor_pool) = descriptor_pool.as_ref() {
1736 for (exec_idx, pipeline) in
1737 pass.execs
1738 .iter()
1739 .enumerate()
1740 .filter_map(|(exec_idx, exec)| {
1741 exec.pipeline.as_ref().map(|pipeline| (exec_idx, pipeline))
1742 })
1743 {
1744 let layouts = pipeline.descriptor_info().layouts.values();
1745 let mut descriptor_sets = Vec::with_capacity(layouts.len());
1746 for descriptor_set_layout in layouts {
1747 descriptor_sets.push(DescriptorPool::allocate_descriptor_set(
1748 descriptor_pool,
1749 descriptor_set_layout,
1750 )?);
1751 }
1752 exec_descriptor_sets.insert(exec_idx, descriptor_sets);
1753 }
1754 }
1755
1756 debug_assert!(!pass.execs.is_empty());
1761 debug_assert!(
1762 pass.execs[0].pipeline.is_none()
1763 || !pass.execs[0].pipeline.as_ref().unwrap().is_graphic()
1764 || pass.execs[0]
1765 .pipeline
1766 .as_ref()
1767 .unwrap()
1768 .unwrap_graphic()
1769 .descriptor_info
1770 .pool_sizes
1771 .values()
1772 .filter_map(|pool| pool.get(&vk::DescriptorType::INPUT_ATTACHMENT))
1773 .next()
1774 .is_none()
1775 );
1776
1777 let render_pass = if pass.execs[0]
1779 .pipeline
1780 .as_ref()
1781 .map(|pipeline| pipeline.is_graphic())
1782 .unwrap_or_default()
1783 {
1784 Some(self.lease_render_pass(pool, pass_idx)?)
1785 } else {
1786 None
1787 };
1788
1789 self.physical_passes.push(PhysicalPass {
1790 descriptor_pool,
1791 exec_descriptor_sets,
1792 render_pass,
1793 });
1794 }
1795
1796 Ok(())
1797 }
1798
1799 #[profiling::function]
1802 fn merge_scheduled_passes(&mut self, schedule: &mut Vec<usize>) {
1803 thread_local! {
1804 static PASSES: RefCell<Vec<Option<Pass>>> = Default::default();
1805 }
1806
1807 PASSES.with_borrow_mut(|passes| {
1808 debug_assert!(passes.is_empty());
1809
1810 passes.extend(self.graph.passes.drain(..).map(Some));
1811
1812 let mut idx = 0;
1813
1814 while idx < schedule.len() {
1817 let mut pass = passes[schedule[idx]].take().unwrap();
1818
1819 let start = idx + 1;
1821 let mut end = start;
1822 while end < schedule.len() {
1823 let other = passes[schedule[end]].as_ref().unwrap();
1824
1825 debug!(
1826 "attempting to merge [{idx}: {}] with [{end}: {}]",
1827 pass.name, other.name
1828 );
1829
1830 if Self::allow_merge_passes(&pass, other) {
1831 end += 1;
1832 } else {
1833 break;
1834 }
1835 }
1836
1837 if log_enabled!(Trace) && start != end {
1838 trace!("merging {} passes into [{idx}: {}]", end - start, pass.name);
1839 }
1840
1841 {
1843 let mut name_additional = 0;
1844 let mut execs_additional = 0;
1845 for idx in start..end {
1846 let other = passes[schedule[idx]].as_ref().unwrap();
1847 name_additional += other.name.len() + 3;
1848 execs_additional += other.execs.len();
1849 }
1850
1851 pass.name.reserve(name_additional);
1852 pass.execs.reserve(execs_additional);
1853 }
1854
1855 for idx in start..end {
1856 let mut other = passes[schedule[idx]].take().unwrap();
1857 pass.name.push_str(" + ");
1858 pass.name.push_str(other.name.as_str());
1859 pass.execs.append(&mut other.execs);
1860 }
1861
1862 self.graph.passes.push(pass);
1863 idx += 1 + end - start;
1864 }
1865
1866 schedule.truncate(self.graph.passes.len());
1868
1869 for (idx, pass_idx) in schedule.iter_mut().enumerate() {
1870 *pass_idx = idx;
1871 }
1872
1873 for pass in passes.drain(..).flatten() {
1875 self.graph.passes.push(pass);
1876 }
1877 });
1878 }
1879
1880 fn next_subpass(cmd_buf: &CommandBuffer) {
1881 trace!("next_subpass");
1882
1883 unsafe {
1884 cmd_buf
1885 .device
1886 .cmd_next_subpass(**cmd_buf, vk::SubpassContents::INLINE);
1887 }
1888 }
1889
1890 #[profiling::function]
1895 pub fn node_pipeline_stages(&self, node: impl Node) -> vk::PipelineStageFlags {
1896 let node_idx = node.index();
1897 let mut res = Default::default();
1898
1899 'pass: for pass in self.graph.passes.iter() {
1900 for exec in pass.execs.iter() {
1901 if exec.accesses.contains_key(&node_idx) {
1902 res |= pass
1903 .execs
1904 .iter()
1905 .filter_map(|exec| exec.pipeline.as_ref())
1906 .map(|pipeline| pipeline.stage())
1907 .reduce(|j, k| j | k)
1908 .unwrap_or(vk::PipelineStageFlags::TRANSFER);
1909
1910 continue 'pass;
1912 }
1913 }
1914 }
1915
1916 debug_assert_ne!(
1917 res,
1918 Default::default(),
1919 "The given node was not accessed in this graph"
1920 );
1921
1922 res
1923 }
1924
1925 #[profiling::function]
1926 fn record_execution_barriers<'a>(
1927 cmd_buf: &CommandBuffer,
1928 bindings: &mut [Binding],
1929 accesses: impl Iterator<Item = (&'a NodeIndex, &'a Vec<SubresourceAccess>)>,
1930 ) {
1931 use std::slice::from_ref;
1932
1933 thread_local! {
1935 static TLS: RefCell<Tls> = Default::default();
1936 }
1937
1938 struct Barrier<T> {
1939 next_access: AccessType,
1940 prev_access: AccessType,
1941 resource: T,
1942 }
1943
1944 struct BufferResource {
1945 buffer: vk::Buffer,
1946 offset: usize,
1947 size: usize,
1948 }
1949
1950 struct ImageResource {
1951 image: vk::Image,
1952 range: vk::ImageSubresourceRange,
1953 }
1954
1955 #[derive(Default)]
1956 struct Tls {
1957 buffers: Vec<Barrier<BufferResource>>,
1958 images: Vec<Barrier<ImageResource>>,
1959 next_accesses: Vec<AccessType>,
1960 prev_accesses: Vec<AccessType>,
1961 }
1962
1963 TLS.with_borrow_mut(|tls| {
1964 tls.buffers.clear();
1966 tls.images.clear();
1967 tls.next_accesses.clear();
1968 tls.prev_accesses.clear();
1969
1970 for (node_idx, accesses) in accesses {
1974 let binding = &bindings[*node_idx];
1975
1976 match binding {
1977 Binding::AccelerationStructure(..)
1978 | Binding::AccelerationStructureLease(..) => {
1979 let Some(accel_struct) = binding.as_driver_acceleration_structure() else {
1980 #[cfg(debug_assertions)]
1981 unreachable!();
1982
1983 #[cfg(not(debug_assertions))]
1984 unsafe {
1985 unreachable_unchecked()
1986 }
1987 };
1988
1989 let prev_access = AccelerationStructure::access(
1990 accel_struct,
1991 accesses.last().unwrap().access,
1992 );
1993
1994 tls.next_accesses.extend(
1995 accesses
1996 .iter()
1997 .map(|&SubresourceAccess { access, .. }| access),
1998 );
1999 tls.prev_accesses.push(prev_access);
2000 }
2001 Binding::Buffer(..) | Binding::BufferLease(..) => {
2002 let Some(buffer) = binding.as_driver_buffer() else {
2003 #[cfg(debug_assertions)]
2004 unreachable!();
2005
2006 #[cfg(not(debug_assertions))]
2007 unsafe {
2008 unreachable_unchecked()
2009 }
2010 };
2011
2012 for &SubresourceAccess {
2013 access,
2014 subresource,
2015 } in accesses
2016 {
2017 let Subresource::Buffer(range) = subresource else {
2018 unreachable!()
2019 };
2020
2021 for (prev_access, range) in Buffer::access(buffer, access, range) {
2022 tls.buffers.push(Barrier {
2023 next_access: access,
2024 prev_access,
2025 resource: BufferResource {
2026 buffer: **buffer,
2027 offset: range.start as _,
2028 size: (range.end - range.start) as _,
2029 },
2030 });
2031 }
2032 }
2033 }
2034 Binding::Image(..) | Binding::ImageLease(..) | Binding::SwapchainImage(..) => {
2035 let Some(image) = binding.as_driver_image() else {
2036 #[cfg(debug_assertions)]
2037 unreachable!();
2038
2039 #[cfg(not(debug_assertions))]
2040 unsafe {
2041 unreachable_unchecked()
2042 }
2043 };
2044
2045 for &SubresourceAccess {
2046 access,
2047 subresource,
2048 } in accesses
2049 {
2050 let Subresource::Image(range) = subresource else {
2051 unreachable!()
2052 };
2053
2054 for (prev_access, range) in Image::access(image, access, range) {
2055 tls.images.push(Barrier {
2056 next_access: access,
2057 prev_access,
2058 resource: ImageResource {
2059 image: **image,
2060 range,
2061 },
2062 })
2063 }
2064 }
2065 }
2066 }
2067 }
2068
2069 let global_barrier = if !tls.next_accesses.is_empty() {
2070 trace!(
2072 " global {:?}->{:?}",
2073 tls.next_accesses, tls.prev_accesses
2074 );
2075
2076 Some(GlobalBarrier {
2077 next_accesses: tls.next_accesses.as_slice(),
2078 previous_accesses: tls.prev_accesses.as_slice(),
2079 })
2080 } else {
2081 None
2082 };
2083 let buffer_barriers = tls.buffers.iter().map(
2084 |Barrier {
2085 next_access,
2086 prev_access,
2087 resource,
2088 }| {
2089 let BufferResource {
2090 buffer,
2091 offset,
2092 size,
2093 } = *resource;
2094
2095 trace!(
2096 " buffer {:?} {:?} {:?}->{:?}",
2097 buffer,
2098 offset..offset + size,
2099 prev_access,
2100 next_access,
2101 );
2102
2103 BufferBarrier {
2104 next_accesses: from_ref(next_access),
2105 previous_accesses: from_ref(prev_access),
2106 src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2107 dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2108 buffer,
2109 offset,
2110 size,
2111 }
2112 },
2113 );
2114 let image_barriers = tls.images.iter().map(
2115 |Barrier {
2116 next_access,
2117 prev_access,
2118 resource,
2119 }| {
2120 let ImageResource { image, range } = *resource;
2121
2122 struct ImageSubresourceRangeDebug(vk::ImageSubresourceRange);
2123
2124 impl std::fmt::Debug for ImageSubresourceRangeDebug {
2125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2126 self.0.aspect_mask.fmt(f)?;
2127
2128 f.write_str(" array: ")?;
2129
2130 let array_layers = self.0.base_array_layer
2131 ..self.0.base_array_layer + self.0.layer_count;
2132 array_layers.fmt(f)?;
2133
2134 f.write_str(" mip: ")?;
2135
2136 let mip_levels =
2137 self.0.base_mip_level..self.0.base_mip_level + self.0.level_count;
2138 mip_levels.fmt(f)
2139 }
2140 }
2141
2142 trace!(
2143 " image {:?} {:?} {:?}->{:?}",
2144 image,
2145 ImageSubresourceRangeDebug(range),
2146 prev_access,
2147 next_access,
2148 );
2149
2150 ImageBarrier {
2151 next_accesses: from_ref(next_access),
2152 next_layout: image_access_layout(*next_access),
2153 previous_accesses: from_ref(prev_access),
2154 previous_layout: image_access_layout(*prev_access),
2155 discard_contents: *prev_access == AccessType::Nothing
2156 || is_write_access(*next_access),
2157 src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2158 dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2159 image,
2160 range,
2161 }
2162 },
2163 );
2164
2165 pipeline_barrier(
2166 &cmd_buf.device,
2167 **cmd_buf,
2168 global_barrier,
2169 &buffer_barriers.collect::<Box<[_]>>(),
2170 &image_barriers.collect::<Box<[_]>>(),
2171 );
2172 });
2173 }
2174
2175 #[profiling::function]
2176 fn record_image_layout_transitions(
2177 cmd_buf: &CommandBuffer,
2178 bindings: &mut [Binding],
2179 pass: &mut Pass,
2180 ) {
2181 use std::slice::from_ref;
2182
2183 thread_local! {
2185 static TLS: RefCell<Tls> = Default::default();
2186 }
2187
2188 struct ImageResourceBarrier {
2189 image: vk::Image,
2190 next_access: AccessType,
2191 prev_access: AccessType,
2192 range: vk::ImageSubresourceRange,
2193 }
2194
2195 #[derive(Default)]
2196 struct Tls {
2197 images: Vec<ImageResourceBarrier>,
2198 initial_layouts: HashMap<usize, ImageAccess<bool>>,
2199 }
2200
2201 TLS.with_borrow_mut(|tls| {
2202 tls.images.clear();
2203 tls.initial_layouts.clear();
2204
2205 for (node_idx, accesses) in pass
2206 .execs
2207 .iter_mut()
2208 .flat_map(|exec| exec.accesses.iter())
2209 .map(|(node_idx, accesses)| (*node_idx, accesses))
2210 {
2211 debug_assert!(bindings.get(node_idx).is_some());
2212
2213 let binding = unsafe {
2214 bindings.get_unchecked(node_idx)
2216 };
2217
2218 match binding {
2219 Binding::AccelerationStructure(..)
2220 | Binding::AccelerationStructureLease(..) => {
2221 let Some(accel_struct) = binding.as_driver_acceleration_structure() else {
2222 #[cfg(debug_assertions)]
2223 unreachable!();
2224
2225 #[cfg(not(debug_assertions))]
2226 unsafe {
2227 unreachable_unchecked()
2228 }
2229 };
2230
2231 AccelerationStructure::access(accel_struct, AccessType::Nothing);
2232 }
2233 Binding::Buffer(..) | Binding::BufferLease(..) => {
2234 let Some(buffer) = binding.as_driver_buffer() else {
2235 #[cfg(debug_assertions)]
2236 unreachable!();
2237
2238 #[cfg(not(debug_assertions))]
2239 unsafe {
2240 unreachable_unchecked()
2241 }
2242 };
2243
2244 for subresource_access in accesses {
2245 let &SubresourceAccess {
2246 subresource: Subresource::Buffer(access_range),
2247 ..
2248 } = subresource_access
2249 else {
2250 #[cfg(debug_assertions)]
2251 unreachable!();
2252
2253 #[cfg(not(debug_assertions))]
2254 unsafe {
2255 unreachable_unchecked()
2258 }
2259 };
2260
2261 for _ in Buffer::access(buffer, AccessType::Nothing, access_range) {}
2262 }
2263 }
2264 Binding::Image(..) | Binding::ImageLease(..) | Binding::SwapchainImage(..) => {
2265 let Some(image) = binding.as_driver_image() else {
2266 #[cfg(debug_assertions)]
2267 unreachable!();
2268
2269 #[cfg(not(debug_assertions))]
2270 unsafe {
2271 unreachable_unchecked()
2272 }
2273 };
2274
2275 let initial_layout = tls
2276 .initial_layouts
2277 .entry(node_idx)
2278 .or_insert_with(|| ImageAccess::new(image.info, true));
2279
2280 for subresource_access in accesses {
2281 let &SubresourceAccess {
2282 access,
2283 subresource: Subresource::Image(access_range),
2284 } = subresource_access
2285 else {
2286 #[cfg(debug_assertions)]
2287 unreachable!();
2288
2289 #[cfg(not(debug_assertions))]
2290 unsafe {
2291 unreachable_unchecked()
2294 }
2295 };
2296
2297 for (initial_layout, layout_range) in
2298 initial_layout.access(false, access_range)
2299 {
2300 for (prev_access, range) in
2301 Image::access(image, access, layout_range)
2302 {
2303 if initial_layout {
2304 tls.images.push(ImageResourceBarrier {
2305 image: **image,
2306 next_access: initial_image_layout_access(access),
2307 prev_access,
2308 range,
2309 });
2310 }
2311 }
2312 }
2313 }
2314 }
2315 }
2316 }
2317
2318 let image_barriers = tls.images.iter().map(
2319 |ImageResourceBarrier {
2320 image,
2321 next_access,
2322 prev_access,
2323 range,
2324 }| {
2325 trace!(
2326 " image {:?} {:?} {:?}->{:?}",
2327 image,
2328 ImageSubresourceRangeDebug(*range),
2329 prev_access,
2330 next_access,
2331 );
2332
2333 ImageBarrier {
2334 next_accesses: from_ref(next_access),
2335 next_layout: image_access_layout(*next_access),
2336 previous_accesses: from_ref(prev_access),
2337 previous_layout: image_access_layout(*prev_access),
2338 discard_contents: *prev_access == AccessType::Nothing
2339 || is_write_access(*next_access),
2340 src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2341 dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
2342 image: *image,
2343 range: *range,
2344 }
2345 },
2346 );
2347
2348 pipeline_barrier(
2349 &cmd_buf.device,
2350 **cmd_buf,
2351 None,
2352 &[],
2353 &image_barriers.collect::<Box<_>>(),
2354 );
2355 });
2356 }
2357
2358 #[profiling::function]
2365 pub fn record_node_dependencies<P>(
2366 &mut self,
2367 pool: &mut P,
2368 cmd_buf: &mut CommandBuffer,
2369 node: impl Node,
2370 ) -> Result<(), DriverError>
2371 where
2372 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
2373 {
2374 let node_idx = node.index();
2375
2376 debug_assert!(self.graph.bindings.get(node_idx).is_some());
2377
2378 if let Some(end_pass_idx) = self.graph.first_node_access_pass_index(node) {
2380 self.record_node_passes(pool, cmd_buf, node_idx, end_pass_idx)?;
2381 }
2382
2383 Ok(())
2384 }
2385
2386 #[profiling::function]
2388 pub fn record_node<P>(
2389 &mut self,
2390 pool: &mut P,
2391 cmd_buf: &mut CommandBuffer,
2392 node: impl Node,
2393 ) -> Result<(), DriverError>
2394 where
2395 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
2396 {
2397 let node_idx = node.index();
2398
2399 debug_assert!(self.graph.bindings.get(node_idx).is_some());
2400
2401 if self.graph.passes.is_empty() {
2402 return Ok(());
2403 }
2404
2405 let end_pass_idx = self.graph.passes.len();
2406 self.record_node_passes(pool, cmd_buf, node_idx, end_pass_idx)
2407 }
2408
2409 #[profiling::function]
2410 fn record_node_passes<P>(
2411 &mut self,
2412 pool: &mut P,
2413 cmd_buf: &mut CommandBuffer,
2414 node_idx: usize,
2415 end_pass_idx: usize,
2416 ) -> Result<(), DriverError>
2417 where
2418 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
2419 {
2420 thread_local! {
2421 static SCHEDULE: RefCell<Schedule> = Default::default();
2422 }
2423
2424 SCHEDULE.with_borrow_mut(|schedule| {
2425 schedule.access_cache.update(&self.graph, end_pass_idx);
2426 schedule.passes.clear();
2427
2428 self.schedule_node_passes(node_idx, end_pass_idx, schedule);
2429 self.record_scheduled_passes(pool, cmd_buf, schedule, end_pass_idx)
2430 })
2431 }
2432
2433 #[profiling::function]
2434 fn record_scheduled_passes<P>(
2435 &mut self,
2436 pool: &mut P,
2437 cmd_buf: &mut CommandBuffer,
2438 schedule: &mut Schedule,
2439 end_pass_idx: usize,
2440 ) -> Result<(), DriverError>
2441 where
2442 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
2443 {
2444 if schedule.passes.is_empty() {
2445 return Ok(());
2446 }
2447
2448 #[cfg(debug_assertions)]
2450 if log_enabled!(Debug) && self.graph.debug {
2451 debug!("resolving the following graph:\n\n{:#?}\n\n", self.graph);
2452 }
2453
2454 debug_assert!(
2455 schedule.passes.windows(2).all(|w| w[0] <= w[1]),
2456 "Unsorted schedule"
2457 );
2458
2459 Self::reorder_scheduled_passes(schedule, end_pass_idx);
2461 self.merge_scheduled_passes(&mut schedule.passes);
2462 self.lease_scheduled_resources(pool, &schedule.passes)?;
2463
2464 for pass_idx in schedule.passes.iter().copied() {
2465 let pass = &mut self.graph.passes[pass_idx];
2466
2467 profiling::scope!("Pass", &pass.name);
2468
2469 let physical_pass = &mut self.physical_passes[pass_idx];
2470 let is_graphic = physical_pass.render_pass.is_some();
2471
2472 trace!("recording pass [{}: {}]", pass_idx, pass.name);
2473
2474 if !physical_pass.exec_descriptor_sets.is_empty() {
2475 Self::write_descriptor_sets(cmd_buf, &self.graph.bindings, pass, physical_pass)?;
2476 }
2477
2478 let render_area = if is_graphic {
2479 Self::record_image_layout_transitions(cmd_buf, &mut self.graph.bindings, pass);
2480
2481 let render_area = Self::render_area(&self.graph.bindings, pass);
2482
2483 Self::begin_render_pass(
2484 cmd_buf,
2485 &self.graph.bindings,
2486 pass,
2487 physical_pass,
2488 render_area,
2489 )?;
2490
2491 Some(render_area)
2492 } else {
2493 None
2494 };
2495
2496 for exec_idx in 0..pass.execs.len() {
2497 let render_area = is_graphic.then(|| {
2498 pass.execs[exec_idx]
2499 .render_area
2500 .unwrap_or(render_area.unwrap())
2501 });
2502
2503 let exec = &mut pass.execs[exec_idx];
2504
2505 if is_graphic && exec_idx > 0 {
2506 Self::next_subpass(cmd_buf);
2507 }
2508
2509 if let Some(pipeline) = exec.pipeline.as_mut() {
2510 Self::bind_pipeline(
2511 cmd_buf,
2512 physical_pass,
2513 exec_idx,
2514 pipeline,
2515 exec.depth_stencil,
2516 )?;
2517
2518 if is_graphic {
2519 let render_area = render_area.unwrap();
2520
2521 Self::set_viewport(
2523 cmd_buf,
2524 render_area.x as _,
2525 render_area.y as _,
2526 render_area.width as _,
2527 render_area.height as _,
2528 exec.depth_stencil
2529 .map(|depth_stencil| {
2530 let min = depth_stencil.min.0;
2531 let max = depth_stencil.max.0;
2532 min..max
2533 })
2534 .unwrap_or(0.0..1.0),
2535 );
2536 Self::set_scissor(
2537 cmd_buf,
2538 render_area.x,
2539 render_area.y,
2540 render_area.width,
2541 render_area.height,
2542 );
2543 }
2544
2545 Self::bind_descriptor_sets(cmd_buf, pipeline, physical_pass, exec_idx);
2546 }
2547
2548 if !is_graphic {
2549 Self::record_execution_barriers(
2550 cmd_buf,
2551 &mut self.graph.bindings,
2552 exec.accesses.iter(),
2553 );
2554 }
2555
2556 trace!(" > exec[{exec_idx}]");
2557
2558 {
2559 profiling::scope!("Execute callback");
2560
2561 let exec_func = exec.func.take().unwrap().0;
2562 exec_func(
2563 &cmd_buf.device,
2564 **cmd_buf,
2565 Bindings::new(&self.graph.bindings, exec),
2566 );
2567 }
2568 }
2569
2570 if is_graphic {
2571 self.end_render_pass(cmd_buf);
2572 }
2573 }
2574
2575 thread_local! {
2576 static PASSES: RefCell<Vec<Pass>> = Default::default();
2577 }
2578
2579 PASSES.with_borrow_mut(|passes| {
2580 debug_assert!(passes.is_empty());
2581
2582 schedule.passes.sort_unstable();
2584 while let Some(schedule_idx) = schedule.passes.pop() {
2585 debug_assert!(!self.graph.passes.is_empty());
2586
2587 while let Some(pass) = self.graph.passes.pop() {
2588 let pass_idx = self.graph.passes.len();
2589
2590 if pass_idx == schedule_idx {
2591 CommandBuffer::push_fenced_drop(
2593 cmd_buf,
2594 (pass, self.physical_passes.pop().unwrap()),
2595 );
2596 break;
2597 } else {
2598 debug_assert!(pass_idx > schedule_idx);
2599
2600 passes.push(pass);
2601 }
2602 }
2603 }
2604
2605 debug_assert!(self.physical_passes.is_empty());
2606
2607 self.graph.passes.extend(passes.drain(..).rev());
2609 });
2610
2611 log::trace!("Recorded passes");
2612
2613 Ok(())
2614 }
2615
2616 #[profiling::function]
2618 pub fn record_unscheduled_passes<P>(
2619 &mut self,
2620 pool: &mut P,
2621 cmd_buf: &mut CommandBuffer,
2622 ) -> Result<(), DriverError>
2623 where
2624 P: Pool<DescriptorPoolInfo, DescriptorPool> + Pool<RenderPassInfo, RenderPass>,
2625 {
2626 if self.graph.passes.is_empty() {
2627 return Ok(());
2628 }
2629
2630 thread_local! {
2631 static SCHEDULE: RefCell<Schedule> = Default::default();
2632 }
2633
2634 SCHEDULE.with_borrow_mut(|schedule| {
2635 schedule
2636 .access_cache
2637 .update(&self.graph, self.graph.passes.len());
2638 schedule.passes.clear();
2639 schedule.passes.extend(0..self.graph.passes.len());
2640
2641 self.record_scheduled_passes(pool, cmd_buf, schedule, self.graph.passes.len())
2642 })
2643 }
2644
2645 #[profiling::function]
2646 fn render_area(bindings: &[Binding], pass: &Pass) -> Area {
2647 let first_exec = pass.execs.first().unwrap();
2650
2651 let (mut width, mut height) = (u32::MAX, u32::MAX);
2654 for (attachment_width, attachment_height) in first_exec
2655 .color_clears
2656 .values()
2657 .copied()
2658 .map(|(attachment, _)| attachment)
2659 .chain(first_exec.color_loads.values().copied())
2660 .chain(first_exec.color_stores.values().copied())
2661 .chain(
2662 first_exec
2663 .depth_stencil_clear
2664 .map(|(attachment, _)| attachment),
2665 )
2666 .chain(first_exec.depth_stencil_load)
2667 .chain(first_exec.depth_stencil_store)
2668 .map(|attachment| {
2669 let info = bindings[attachment.target].as_driver_image().unwrap().info;
2670
2671 (
2672 info.width >> attachment.base_mip_level,
2673 info.height >> attachment.base_mip_level,
2674 )
2675 })
2676 {
2677 width = width.min(attachment_width);
2678 height = height.min(attachment_height);
2679 }
2680
2681 Area {
2682 height,
2683 width,
2684 x: 0,
2685 y: 0,
2686 }
2687 }
2688
2689 #[profiling::function]
2690 fn reorder_scheduled_passes(schedule: &mut Schedule, end_pass_idx: usize) {
2691 if schedule.passes.len() < 3 {
2693 return;
2694 }
2695
2696 let mut scheduled = 0;
2697
2698 thread_local! {
2699 static UNSCHEDULED: RefCell<Vec<bool>> = Default::default();
2700 }
2701
2702 UNSCHEDULED.with_borrow_mut(|unscheduled| {
2703 unscheduled.truncate(end_pass_idx);
2704 unscheduled.fill(true);
2705 unscheduled.resize(end_pass_idx, true);
2706
2707 while scheduled < schedule.passes.len() {
2709 let mut best_idx = scheduled;
2710 let pass_idx = schedule.passes[best_idx];
2711 let mut best_overlap_factor = schedule
2712 .access_cache
2713 .interdependent_passes(pass_idx, end_pass_idx)
2714 .count();
2715
2716 for (idx, pass_idx) in schedule.passes[best_idx + 1..schedule.passes.len()]
2717 .iter()
2718 .enumerate()
2719 {
2720 let mut overlap_factor = 0;
2721
2722 for other_pass_idx in schedule
2723 .access_cache
2724 .interdependent_passes(*pass_idx, end_pass_idx)
2725 {
2726 if unscheduled[other_pass_idx] {
2727 break;
2729 }
2730
2731 overlap_factor += 1;
2732 }
2733
2734 if overlap_factor > best_overlap_factor {
2735 best_idx += idx + 1;
2736 best_overlap_factor = overlap_factor;
2737 }
2738 }
2739
2740 unscheduled[schedule.passes[best_idx]] = false;
2741 schedule.passes.swap(scheduled, best_idx);
2742 scheduled += 1;
2743 }
2744 });
2745 }
2746
2747 #[profiling::function]
2750 fn schedule_node_passes(&self, node_idx: usize, end_pass_idx: usize, schedule: &mut Schedule) {
2751 type UnscheduledUnresolvedUnchecked = (Vec<bool>, Vec<bool>, VecDeque<(usize, usize)>);
2752
2753 thread_local! {
2754 static UNSCHEDULED_UNRESOLVED_UNCHECKED: RefCell<UnscheduledUnresolvedUnchecked> = Default::default();
2755 }
2756
2757 UNSCHEDULED_UNRESOLVED_UNCHECKED.with_borrow_mut(|(unscheduled, unresolved, unchecked)| {
2758 unscheduled.truncate(end_pass_idx);
2759 unscheduled.fill(true);
2760 unscheduled.resize(end_pass_idx, true);
2761
2762 unresolved.truncate(self.graph.bindings.len());
2763 unresolved.fill(true);
2764 unresolved.resize(self.graph.bindings.len(), true);
2765
2766 debug_assert!(unchecked.is_empty());
2767
2768 trace!("scheduling node {node_idx}");
2769
2770 unresolved[node_idx] = false;
2771
2772 for pass_idx in schedule
2774 .access_cache
2775 .dependent_passes(node_idx, end_pass_idx)
2776 {
2777 trace!(
2778 " pass [{pass_idx}: {}] is dependent",
2779 self.graph.passes[pass_idx].name
2780 );
2781
2782 debug_assert!(unscheduled[pass_idx]);
2783
2784 unscheduled[pass_idx] = false;
2785 schedule.passes.push(pass_idx);
2786
2787 for node_idx in schedule.access_cache.dependent_nodes(pass_idx) {
2788 trace!(" node {node_idx} is dependent");
2789
2790 let unresolved = &mut unresolved[node_idx];
2791 if *unresolved {
2792 *unresolved = false;
2793 unchecked.push_back((node_idx, pass_idx));
2794 }
2795 }
2796 }
2797
2798 trace!("secondary passes below");
2799
2800 while let Some((node_idx, pass_idx)) = unchecked.pop_front() {
2802 trace!(" node {node_idx} is dependent");
2803
2804 for pass_idx in schedule
2805 .access_cache
2806 .dependent_passes(node_idx, pass_idx + 1)
2807 {
2808 let unscheduled = &mut unscheduled[pass_idx];
2809 if *unscheduled {
2810 *unscheduled = false;
2811 schedule.passes.push(pass_idx);
2812
2813 trace!(
2814 " pass [{pass_idx}: {}] is dependent",
2815 self.graph.passes[pass_idx].name
2816 );
2817
2818 for node_idx in schedule.access_cache.dependent_nodes(pass_idx) {
2819 trace!(" node {node_idx} is dependent");
2820
2821 let unresolved = &mut unresolved[node_idx];
2822 if *unresolved {
2823 *unresolved = false;
2824 unchecked.push_back((node_idx, pass_idx));
2825 }
2826 }
2827 }
2828 }
2829 }
2830
2831 schedule.passes.sort_unstable();
2832
2833 if log_enabled!(Debug) {
2834 if !schedule.passes.is_empty() {
2835 debug!(
2837 "schedule: {}",
2838 schedule
2839 .passes
2840 .iter()
2841 .copied()
2842 .map(|idx| format!("[{}: {}]", idx, self.graph.passes[idx].name))
2843 .collect::<Vec<_>>()
2844 .join(", ")
2845 );
2846 }
2847
2848 if log_enabled!(Trace) {
2849 let unscheduled = (0..end_pass_idx)
2850 .filter(|&pass_idx| unscheduled[pass_idx])
2851 .collect::<Box<_>>();
2852
2853 if !unscheduled.is_empty() {
2854 trace!(
2857 "delaying: {}",
2858 unscheduled
2859 .iter()
2860 .copied()
2861 .map(|idx| format!("[{}: {}]", idx, self.graph.passes[idx].name))
2862 .collect::<Vec<_>>()
2863 .join(", ")
2864 );
2865 }
2866
2867 if end_pass_idx < self.graph.passes.len() {
2868 trace!(
2871 "ignoring: {}",
2872 self.graph.passes[end_pass_idx..]
2873 .iter()
2874 .enumerate()
2875 .map(|(idx, pass)| format!(
2876 "[{}: {}]",
2877 idx + end_pass_idx,
2878 pass.name
2879 ))
2880 .collect::<Vec<_>>()
2881 .join(", ")
2882 );
2883 }
2884 }
2885 }
2886 });
2887 }
2888
2889 fn set_scissor(cmd_buf: &CommandBuffer, x: i32, y: i32, width: u32, height: u32) {
2890 use std::slice::from_ref;
2891
2892 unsafe {
2893 cmd_buf.device.cmd_set_scissor(
2894 **cmd_buf,
2895 0,
2896 from_ref(&vk::Rect2D {
2897 extent: vk::Extent2D { width, height },
2898 offset: vk::Offset2D { x, y },
2899 }),
2900 );
2901 }
2902 }
2903
2904 fn set_viewport(
2905 cmd_buf: &CommandBuffer,
2906 x: f32,
2907 y: f32,
2908 width: f32,
2909 height: f32,
2910 depth: Range<f32>,
2911 ) {
2912 use std::slice::from_ref;
2913
2914 unsafe {
2915 cmd_buf.device.cmd_set_viewport(
2916 **cmd_buf,
2917 0,
2918 from_ref(&vk::Viewport {
2919 x,
2920 y,
2921 width,
2922 height,
2923 min_depth: depth.start,
2924 max_depth: depth.end,
2925 }),
2926 );
2927 }
2928 }
2929
2930 #[profiling::function]
2932 pub fn submit<P>(
2933 mut self,
2934 pool: &mut P,
2935 queue_family_index: usize,
2936 queue_index: usize,
2937 ) -> Result<Lease<CommandBuffer>, DriverError>
2938 where
2939 P: Pool<CommandBufferInfo, CommandBuffer>
2940 + Pool<DescriptorPoolInfo, DescriptorPool>
2941 + Pool<RenderPassInfo, RenderPass>,
2942 {
2943 use std::slice::from_ref;
2944
2945 trace!("submit");
2946
2947 let mut cmd_buf = pool.lease(CommandBufferInfo::new(queue_family_index as _))?;
2948
2949 debug_assert!(
2950 queue_family_index < cmd_buf.device.physical_device.queue_families.len(),
2951 "Queue family index must be within the range of the available queues created by the device."
2952 );
2953 debug_assert!(
2954 queue_index
2955 < cmd_buf.device.physical_device.queue_families[queue_family_index].queue_count
2956 as usize,
2957 "Queue index must be within the range of the available queues created by the device."
2958 );
2959
2960 CommandBuffer::wait_until_executed(&mut cmd_buf)?;
2961
2962 unsafe {
2963 cmd_buf
2964 .device
2965 .begin_command_buffer(
2966 **cmd_buf,
2967 &vk::CommandBufferBeginInfo::default()
2968 .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
2969 )
2970 .map_err(|_| DriverError::OutOfMemory)?;
2971 }
2972
2973 self.record_unscheduled_passes(pool, &mut cmd_buf)?;
2974
2975 unsafe {
2976 cmd_buf
2977 .device
2978 .end_command_buffer(**cmd_buf)
2979 .map_err(|_| DriverError::OutOfMemory)?;
2980 cmd_buf
2981 .device
2982 .reset_fences(from_ref(&cmd_buf.fence))
2983 .map_err(|_| DriverError::OutOfMemory)?;
2984 cmd_buf
2985 .device
2986 .queue_submit(
2987 cmd_buf.device.queues[queue_family_index][queue_index],
2988 from_ref(&vk::SubmitInfo::default().command_buffers(from_ref(&cmd_buf))),
2989 cmd_buf.fence,
2990 )
2991 .map_err(|_| DriverError::OutOfMemory)?;
2992 }
2993
2994 cmd_buf.waiting = true;
2995
2996 CommandBuffer::push_fenced_drop(&mut cmd_buf, self);
3002
3003 Ok(cmd_buf)
3004 }
3005
3006 pub(crate) fn swapchain_image(&mut self, node: SwapchainImageNode) -> &SwapchainImage {
3007 let Some(swapchain_image) = self.graph.bindings[node.idx].as_swapchain_image() else {
3008 panic!("invalid swapchain image node");
3009 };
3010
3011 swapchain_image
3012 }
3013
3014 #[profiling::function]
3015 fn write_descriptor_sets(
3016 cmd_buf: &CommandBuffer,
3017 bindings: &[Binding],
3018 pass: &Pass,
3019 physical_pass: &PhysicalPass,
3020 ) -> Result<(), DriverError> {
3021 struct IndexWrite<'a> {
3022 idx: usize,
3023 write: vk::WriteDescriptorSet<'a>,
3024 }
3025
3026 #[derive(Default)]
3027 struct Tls<'a> {
3028 accel_struct_infos: Vec<vk::WriteDescriptorSetAccelerationStructureKHR<'a>>,
3029 accel_struct_writes: Vec<IndexWrite<'a>>,
3030 buffer_infos: Vec<vk::DescriptorBufferInfo>,
3031 buffer_writes: Vec<IndexWrite<'a>>,
3032 descriptors: Vec<vk::WriteDescriptorSet<'a>>,
3033 image_infos: Vec<vk::DescriptorImageInfo>,
3034 image_writes: Vec<IndexWrite<'a>>,
3035 }
3036
3037 let mut tls = Tls::default();
3038
3039 for (exec_idx, exec, pipeline) in pass
3040 .execs
3041 .iter()
3042 .enumerate()
3043 .filter_map(|(exec_idx, exec)| {
3044 exec.pipeline
3045 .as_ref()
3046 .map(|pipeline| (exec_idx, exec, pipeline))
3047 })
3048 .filter(|(.., pipeline)| !pipeline.descriptor_info().layouts.is_empty())
3049 {
3050 let descriptor_sets = &physical_pass.exec_descriptor_sets[&exec_idx];
3051
3052 for (descriptor, (node_idx, view_info)) in exec.bindings.iter() {
3054 let (descriptor_set_idx, dst_binding, binding_offset) = descriptor.into_tuple();
3055 let (descriptor_info, _) = pipeline
3056 .descriptor_bindings()
3057 .get(&Descriptor { set: descriptor_set_idx, binding: dst_binding })
3058 .unwrap_or_else(|| panic!("descriptor {descriptor_set_idx}.{dst_binding}[{binding_offset}] specified in recorded execution of pass \"{}\" was not discovered through shader reflection", &pass.name));
3059 let descriptor_type = descriptor_info.descriptor_type();
3060 let bound_node = &bindings[*node_idx];
3061 if let Some(image) = bound_node.as_driver_image() {
3062 let view_info = view_info.as_ref().unwrap();
3063 let mut image_view_info = *view_info.as_image().unwrap();
3064
3065 if image_view_info.aspect_mask.is_empty() {
3067 image_view_info.aspect_mask = format_aspect_mask(image.info.fmt);
3068 }
3069
3070 let image_view = Image::view(image, image_view_info)?;
3071 let image_layout = match descriptor_type {
3072 vk::DescriptorType::COMBINED_IMAGE_SAMPLER
3073 | vk::DescriptorType::SAMPLED_IMAGE => {
3074 if image_view_info.aspect_mask.contains(
3075 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
3076 ) {
3077 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
3078 } else if image_view_info
3079 .aspect_mask
3080 .contains(vk::ImageAspectFlags::DEPTH)
3081 {
3082 vk::ImageLayout::DEPTH_READ_ONLY_OPTIMAL
3083 } else if image_view_info
3084 .aspect_mask
3085 .contains(vk::ImageAspectFlags::STENCIL)
3086 {
3087 vk::ImageLayout::STENCIL_READ_ONLY_OPTIMAL
3088 } else {
3089 vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL
3090 }
3091 }
3092 vk::DescriptorType::STORAGE_IMAGE => vk::ImageLayout::GENERAL,
3093 _ => unimplemented!("{descriptor_type:?}"),
3094 };
3095
3096 if binding_offset == 0 {
3097 tls.image_writes.push(IndexWrite {
3098 idx: tls.image_infos.len(),
3099 write: vk::WriteDescriptorSet {
3100 dst_set: *descriptor_sets[descriptor_set_idx as usize],
3101 dst_binding,
3102 descriptor_type,
3103 descriptor_count: 1,
3104 ..Default::default()
3105 },
3106 });
3107 } else {
3108 tls.image_writes.last_mut().unwrap().write.descriptor_count += 1;
3109 }
3110
3111 tls.image_infos.push(
3112 vk::DescriptorImageInfo::default()
3113 .image_layout(image_layout)
3114 .image_view(image_view),
3115 );
3116 } else if let Some(buffer) = bound_node.as_driver_buffer() {
3117 let view_info = view_info.as_ref().unwrap();
3118 let buffer_view_info = view_info.as_buffer().unwrap();
3119
3120 if binding_offset == 0 {
3121 tls.buffer_writes.push(IndexWrite {
3122 idx: tls.buffer_infos.len(),
3123 write: vk::WriteDescriptorSet {
3124 dst_set: *descriptor_sets[descriptor_set_idx as usize],
3125 dst_binding,
3126 descriptor_type,
3127 descriptor_count: 1,
3128 ..Default::default()
3129 },
3130 });
3131 } else {
3132 tls.buffer_writes.last_mut().unwrap().write.descriptor_count += 1;
3133 }
3134
3135 tls.buffer_infos.push(
3136 vk::DescriptorBufferInfo::default()
3137 .buffer(**buffer)
3138 .offset(buffer_view_info.start)
3139 .range(buffer_view_info.end - buffer_view_info.start),
3140 );
3141 } else if let Some(accel_struct) = bound_node.as_driver_acceleration_structure() {
3142 if binding_offset == 0 {
3143 tls.accel_struct_writes.push(IndexWrite {
3144 idx: tls.accel_struct_infos.len(),
3145 write: vk::WriteDescriptorSet::default()
3146 .dst_set(*descriptor_sets[descriptor_set_idx as usize])
3147 .dst_binding(dst_binding)
3148 .descriptor_type(descriptor_type)
3149 .descriptor_count(1),
3150 });
3151 } else {
3152 tls.accel_struct_writes
3153 .last_mut()
3154 .unwrap()
3155 .write
3156 .descriptor_count += 1;
3157 }
3158
3159 tls.accel_struct_infos.push(
3160 vk::WriteDescriptorSetAccelerationStructureKHR::default()
3161 .acceleration_structures(std::slice::from_ref(accel_struct)),
3162 );
3163 } else {
3164 unimplemented!();
3165 }
3166 }
3167
3168 if let ExecutionPipeline::Graphic(pipeline) = pipeline {
3169 if exec_idx > 0 {
3171 for (
3172 &Descriptor {
3173 set: descriptor_set_idx,
3174 binding: dst_binding,
3175 },
3176 (descriptor_info, _),
3177 ) in &pipeline.descriptor_bindings
3178 {
3179 if let DescriptorInfo::InputAttachment(_, attachment_idx) = *descriptor_info
3180 {
3181 let is_random_access = exec.color_stores.contains_key(&attachment_idx)
3182 || exec.color_resolves.contains_key(&attachment_idx);
3183 let (attachment, write_exec) = pass.execs[0..exec_idx]
3184 .iter()
3185 .rev()
3186 .find_map(|exec| {
3187 exec.color_stores
3188 .get(&attachment_idx)
3189 .copied()
3190 .map(|attachment| (attachment, exec))
3191 .or_else(|| {
3192 exec.color_resolves.get(&attachment_idx).map(
3193 |(resolved_attachment, _)| {
3194 (*resolved_attachment, exec)
3195 },
3196 )
3197 })
3198 })
3199 .expect("input attachment not written");
3200 let late = &write_exec.accesses[&attachment.target].last().unwrap();
3201 let image_range = late.subresource.as_image().unwrap();
3202 let image_binding = &bindings[attachment.target];
3203 let image = image_binding.as_driver_image().unwrap();
3204 let image_view_info = ImageViewInfo {
3205 array_layer_count: image_range.layer_count,
3206 aspect_mask: attachment.aspect_mask,
3207 base_array_layer: image_range.base_array_layer,
3208 base_mip_level: image_range.base_mip_level,
3209 fmt: attachment.format,
3210 mip_level_count: image_range.level_count,
3211 ty: image.info.ty,
3212 };
3213 let image_view = Image::view(image, image_view_info)?;
3214
3215 tls.image_writes.push(IndexWrite {
3216 idx: tls.image_infos.len(),
3217 write: vk::WriteDescriptorSet {
3218 dst_set: *descriptor_sets[descriptor_set_idx as usize],
3219 dst_binding,
3220 descriptor_type: vk::DescriptorType::INPUT_ATTACHMENT,
3221 descriptor_count: 1,
3222 ..Default::default()
3223 },
3224 });
3225
3226 tls.image_infos.push(vk::DescriptorImageInfo {
3227 image_layout: Self::attachment_layout(
3228 attachment.aspect_mask,
3229 is_random_access,
3230 true,
3231 ),
3232 image_view,
3233 sampler: vk::Sampler::null(),
3234 });
3235 }
3236 }
3237 }
3238 }
3239 }
3240
3241 tls.descriptors
3244 .extend(tls.accel_struct_writes.drain(..).map(
3245 |IndexWrite { idx, mut write }| unsafe {
3246 write.p_next = tls.accel_struct_infos.as_ptr().add(idx) as *const _;
3247 write
3248 },
3249 ));
3250 tls.descriptors.extend(tls.buffer_writes.drain(..).map(
3251 |IndexWrite { idx, mut write }| unsafe {
3252 write.p_buffer_info = tls.buffer_infos.as_ptr().add(idx);
3253 write
3254 },
3255 ));
3256 tls.descriptors.extend(tls.image_writes.drain(..).map(
3257 |IndexWrite { idx, mut write }| unsafe {
3258 write.p_image_info = tls.image_infos.as_ptr().add(idx);
3259 write
3260 },
3261 ));
3262
3263 if !tls.descriptors.is_empty() {
3264 trace!(
3265 " writing {} descriptors ({} buffers, {} images)",
3266 tls.descriptors.len(),
3267 tls.buffer_infos.len(),
3268 tls.image_infos.len()
3269 );
3270
3271 unsafe {
3272 cmd_buf
3273 .device
3274 .update_descriptor_sets(tls.descriptors.as_slice(), &[]);
3275 }
3276 }
3277
3278 Ok(())
3279 }
3280}
3281
3282#[derive(Default)]
3283struct Schedule {
3284 access_cache: AccessCache,
3285 passes: Vec<usize>,
3286}