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