1#![deny(missing_docs)]
15#![deny(rustdoc::broken_intra_doc_links)]
16
17pub mod cmd;
18pub mod driver;
19pub mod node;
20pub mod pool;
21pub mod stream;
22pub mod submission;
23
24#[doc(hidden)]
25pub use self::fixture::Fixture;
26
27mod fixture;
28mod lazy_str;
29
30pub use self::lazy_str::LazyStr;
31
32use {
33 self::{
34 cmd::{AttachmentIndex, Binding, Command, SubresourceAccess, ViewInfo},
35 node::{
36 AccelerationStructureLeaseNode, AccelerationStructureNode,
37 AnyAccelerationStructureNode, AnyBufferNode, AnyImageNode, BufferLeaseNode, BufferNode,
38 ImageLeaseNode, ImageNode, SwapchainImageNode,
39 },
40 },
41 crate::{
42 cmd::{ClearColorValue, CommandRef},
43 driver::{
44 DescriptorBindingMap,
45 accel_struct::AccelerationStructureInfo,
46 buffer::BufferInfo,
47 compute::ComputePipeline,
48 descriptor_set::DescriptorSet,
49 format_aspect_mask,
50 graphics::{DepthStencilInfo, GraphicsPipeline},
51 image::{ImageInfo, ImageViewInfo, SampleCount},
52 ray_tracing::RayTracingPipeline,
53 render_pass::ResolveMode,
54 shader::PipelineDescriptorInfo,
55 },
56 driver::{
57 accel_struct::AccelerationStructure, buffer::Buffer, image::Image,
58 swapchain::SwapchainImage,
59 },
60 pool::Lease,
61 submission::Submission,
62 },
63 ash::vk,
64 smallvec::SmallVec,
65 std::{
66 cell::RefCell,
67 cmp::Ord,
68 collections::{BTreeMap, HashMap},
69 fmt::{Debug, Formatter},
70 mem,
71 ops::{Deref, DerefMut, Range},
72 slice::Iter,
73 sync::{
74 Arc,
75 atomic::{AtomicU8, Ordering},
76 },
77 },
78 vk_sync::AccessType,
79};
80
81#[cfg(feature = "checked")]
82use std::sync::atomic::AtomicU64;
83
84type CommandFn = Arc<dyn for<'a> Fn(CommandRef<'a>) + Send + Sync>;
85type CommandFnOnce = Box<dyn FnOnce(CommandRef) + Send>;
86type NodeIndex = usize;
87
88#[derive(Debug)]
89struct AtomicCommandExecution(AtomicU8);
90
91impl AtomicCommandExecution {
92 const PENDING: u8 = 0xf0;
93 const EXECUTED: u8 = 0xf1;
94 const ABANDONED: u8 = 0xf2;
95
96 fn new_pending() -> Arc<Self> {
97 Arc::new(Self(AtomicU8::new(Self::PENDING)))
98 }
99
100 fn compare_pending_exchange_abandoned(&self) {
101 let _ = self.0.compare_exchange(
102 Self::PENDING,
103 Self::ABANDONED,
104 Ordering::AcqRel,
105 Ordering::Acquire,
106 );
107 }
108
109 fn compare_pending_exchange_executed(&self) {
110 let _ = self.0.compare_exchange(
111 Self::PENDING,
112 Self::EXECUTED,
113 Ordering::AcqRel,
114 Ordering::Acquire,
115 );
116 }
117
118 fn load(&self) -> u8 {
119 self.0.load(Ordering::Acquire)
120 }
121}
122
123impl Drop for AtomicCommandExecution {
124 fn drop(&mut self) {
125 self.compare_pending_exchange_abandoned();
126 }
127}
128
129#[derive(Clone, Debug)]
131pub struct CommandExecution(Arc<AtomicCommandExecution>);
132
133impl CommandExecution {
134 pub fn has_executed(&self) -> Result<bool, CommandExecutionAbandoned> {
139 match self.0.load() {
140 AtomicCommandExecution::PENDING => Ok(false),
141 AtomicCommandExecution::EXECUTED => Ok(true),
142 _ => Err(CommandExecutionAbandoned),
143 }
144 }
145}
146
147#[derive(Clone, Copy, Debug, Eq, PartialEq)]
149pub struct CommandExecutionAbandoned;
150
151impl From<CommandExecutionAbandoned> for crate::driver::DriverError {
152 fn from(_: CommandExecutionAbandoned) -> Self {
153 Self::InvalidData
154 }
155}
156
157#[derive(Debug, Default)]
158enum CommandExecutions {
159 #[default]
160 None,
161 One(Arc<AtomicCommandExecution>),
162 Many(Arc<[Arc<AtomicCommandExecution>]>),
163}
164
165impl Clone for CommandExecutions {
166 fn clone(&self) -> Self {
167 Self::None
168 }
169}
170
171impl CommandExecutions {
172 fn signal_abandoned(&self) {
173 self.for_each(AtomicCommandExecution::compare_pending_exchange_abandoned);
174 }
175
176 fn signal_executed(&self) {
177 self.for_each(AtomicCommandExecution::compare_pending_exchange_executed);
178 }
179
180 fn extend(&mut self, other: Self) {
181 match (mem::take(self), other) {
182 (Self::None, rhs) => *self = rhs,
183 (lhs, Self::None) => *self = lhs,
184 (Self::One(lhs), Self::One(rhs)) => *self = Self::Many(Arc::from([lhs, rhs])),
185 (Self::One(lhs), Self::Many(rhs)) => {
186 let mut states = Vec::with_capacity(rhs.len() + 1);
187 states.push(lhs);
188 states.extend(rhs.iter().cloned());
189 *self = Self::Many(Arc::from(states));
190 }
191 (Self::Many(lhs), Self::One(rhs)) => {
192 let mut states = Vec::with_capacity(lhs.len() + 1);
193 states.extend(lhs.iter().cloned());
194 states.push(rhs);
195 *self = Self::Many(Arc::from(states));
196 }
197 (Self::Many(lhs), Self::Many(rhs)) => {
198 let mut states = Vec::with_capacity(lhs.len() + rhs.len());
199 states.extend(lhs.iter().cloned());
200 states.extend(rhs.iter().cloned());
201 *self = Self::Many(Arc::from(states));
202 }
203 }
204 }
205
206 fn for_each(&self, mut f: impl FnMut(&AtomicCommandExecution)) {
207 match self {
208 Self::None => {}
209 Self::One(state) => f(state),
210 Self::Many(states) => {
211 for state in states.iter() {
212 f(state);
213 }
214 }
215 }
216 }
217
218 fn track(&mut self) -> CommandExecution {
219 let tracker = AtomicCommandExecution::new_pending();
220 let cmd_exec = CommandExecution(tracker.clone());
221 self.extend(Self::One(tracker));
222
223 cmd_exec
224 }
225}
226
227#[cfg(feature = "checked")]
228#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
229pub(crate) struct GraphId(u64);
230
231#[cfg(feature = "checked")]
232impl GraphId {
233 fn next() -> Self {
234 static NEXT_ID: AtomicU64 = AtomicU64::new(1);
235
236 Self(NEXT_ID.fetch_add(1, Ordering::Relaxed))
237 }
238}
239
240#[derive(Debug)]
241enum AnyResource {
242 AccelerationStructure(Arc<AccelerationStructure>),
243 AccelerationStructureArg(AccelerationStructureInfo),
244 AccelerationStructureLease(Arc<Lease<AccelerationStructure>>),
245 Buffer(Arc<Buffer>),
246 BufferArg(BufferInfo),
247 BufferLease(Arc<Lease<Buffer>>),
248 Image(Arc<Image>),
249 ImageArg(ImageInfo),
250 ImageLease(Arc<Lease<Image>>),
251 SwapchainImage(Box<SwapchainImage>),
252}
253
254impl Clone for AnyResource {
255 fn clone(&self) -> Self {
256 match self {
257 Self::AccelerationStructure(resource) => {
258 Self::AccelerationStructure(Arc::clone(resource))
259 }
260 Self::AccelerationStructureArg(info) => Self::AccelerationStructureArg(*info),
261 Self::AccelerationStructureLease(resource) => {
262 Self::AccelerationStructureLease(Arc::clone(resource))
263 }
264 Self::Buffer(resource) => Self::Buffer(Arc::clone(resource)),
265 Self::BufferArg(info) => Self::BufferArg(*info),
266 Self::BufferLease(resource) => Self::BufferLease(Arc::clone(resource)),
267 Self::Image(resource) => Self::Image(Arc::clone(resource)),
268 Self::ImageArg(info) => Self::ImageArg(*info),
269 Self::ImageLease(resource) => Self::ImageLease(Arc::clone(resource)),
270 Self::SwapchainImage(resource) => {
271 Self::SwapchainImage(Box::new(unsafe { resource.to_detached() }))
272 }
273 }
274 }
275}
276
277macro_rules! any_resource_from_arc {
278 ($name:ident) => {
279 paste::paste! {
280 impl From<Arc<$name>> for AnyResource {
281 fn from(resource: Arc<$name>) -> Self {
282 Self::$name(resource)
283 }
284 }
285
286 impl From<Arc<Lease<$name>>> for AnyResource {
287 fn from(resource: Arc<Lease<$name>>) -> Self {
288 Self::[<$name Lease>](resource)
289 }
290 }
291 }
292 };
293}
294
295any_resource_from_arc!(AccelerationStructure);
296any_resource_from_arc!(Buffer);
297any_resource_from_arc!(Image);
298
299impl AnyResource {
300 fn as_accel_struct(&self) -> Option<&AccelerationStructure> {
301 Some(match self {
302 Self::AccelerationStructure(resource) => resource,
303 Self::AccelerationStructureLease(resource) => resource,
304 _ => return None,
305 })
306 }
307
308 fn as_buffer(&self) -> Option<&Buffer> {
309 Some(match self {
310 Self::Buffer(resource) => resource,
311 Self::BufferLease(resource) => resource,
312 _ => return None,
313 })
314 }
315
316 fn as_image(&self) -> Option<&Image> {
317 Some(match self {
318 Self::Image(resource) => resource,
319 Self::ImageLease(resource) => resource,
320 Self::SwapchainImage(resource) => resource,
321 _ => return None,
322 })
323 }
324
325 fn expect_accel_struct(&self) -> &AccelerationStructure {
326 self.as_accel_struct()
327 .expect("missing acceleration structure resource")
328 }
329
330 pub(crate) fn expect_accel_struct_info(
331 &self,
332 ) -> crate::driver::accel_struct::AccelerationStructureInfo {
333 match self {
334 Self::AccelerationStructure(resource) => resource.info,
335 Self::AccelerationStructureArg(info) => *info,
336 Self::AccelerationStructureLease(resource) => resource.info,
337 _ => panic!("missing acceleration structure resource"),
338 }
339 }
340
341 fn expect_buffer(&self) -> &Buffer {
342 self.as_buffer().expect("missing buffer resource")
343 }
344
345 pub(crate) fn expect_buffer_info(&self) -> crate::driver::buffer::BufferInfo {
346 match self {
347 Self::Buffer(resource) => resource.info,
348 Self::BufferArg(info) => *info,
349 Self::BufferLease(resource) => resource.info,
350 _ => panic!("missing buffer resource"),
351 }
352 }
353
354 fn expect_image(&self) -> &Image {
355 self.as_image().expect("missing image resource")
356 }
357
358 pub(crate) fn expect_image_info(&self) -> ImageInfo {
359 match self {
360 Self::Image(resource) => resource.info,
361 Self::ImageArg(info) => *info,
362 Self::ImageLease(resource) => resource.info,
363 Self::SwapchainImage(resource) => resource.info,
364 _ => panic!("missing image resource"),
365 }
366 }
367}
368
369#[derive(Clone, Copy, Debug)]
370struct Attachment {
371 array_layer_count: u32,
372 aspect_mask: vk::ImageAspectFlags,
373 base_array_layer: u32,
374 base_mip_level: u32,
375 format: vk::Format,
376 mip_level_count: u32,
377 sample_count: SampleCount,
378 target: NodeIndex,
379}
380
381impl Attachment {
382 fn new(image_view_info: ImageViewInfo, sample_count: SampleCount, target: NodeIndex) -> Self {
383 Self {
384 array_layer_count: image_view_info.array_layer_count,
385 aspect_mask: image_view_info.aspect_mask,
386 base_array_layer: image_view_info.base_array_layer,
387 base_mip_level: image_view_info.base_mip_level,
388 format: image_view_info.format,
389 mip_level_count: image_view_info.mip_level_count,
390 sample_count,
391 target,
392 }
393 }
394
395 fn are_compatible(lhs: Option<Self>, rhs: Option<Self>) -> bool {
396 let (Some(lhs), Some(rhs)) = (lhs, rhs) else {
400 return true;
401 };
402
403 Self::are_identical(lhs, rhs)
404 }
405
406 fn are_identical(lhs: Self, rhs: Self) -> bool {
407 lhs.array_layer_count == rhs.array_layer_count
408 && lhs.base_array_layer == rhs.base_array_layer
409 && lhs.base_mip_level == rhs.base_mip_level
410 && lhs.format == rhs.format
411 && lhs.mip_level_count == rhs.mip_level_count
412 && lhs.sample_count == rhs.sample_count
413 && lhs.target == rhs.target
414 }
415
416 fn image_view_info(self, image_info: ImageInfo) -> ImageViewInfo {
417 image_info
418 .into_builder()
419 .array_layer_count(self.array_layer_count)
420 .mip_level_count(self.mip_level_count)
421 .format(self.format)
422 .into_image_view()
423 .aspect_mask(self.aspect_mask)
424 .base_array_layer(self.base_array_layer)
425 .base_mip_level(self.base_mip_level)
426 .build()
427 }
428
429 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
430 self.target = node_map[self.target];
431 }
432}
433
434#[derive(Clone, Copy, Debug)]
435struct ColorAttachment {
436 attachment: Attachment,
437 load: LoadOp<[f32; 4]>,
438 store: StoreOp,
439 resolve: Option<ColorResolve>,
440 is_input: bool,
441 is_attachment: bool,
442}
443
444#[derive(Clone, Debug, Default)]
445struct ExecutionAttachmentMap {
446 color: Vec<Option<ColorAttachment>>,
447 depth_stencil: Option<DepthStencilAttachment>,
448}
449
450impl ExecutionAttachmentMap {
451 fn color_attachment(&self, attachment_idx: AttachmentIndex) -> Option<&ColorAttachment> {
452 self.color
453 .get(attachment_idx as usize)
454 .and_then(|slot| slot.as_ref())
455 }
456
457 fn color_attachment_mut(
458 &mut self,
459 attachment_idx: AttachmentIndex,
460 ) -> Option<&mut ColorAttachment> {
461 self.color
462 .get_mut(attachment_idx as usize)
463 .and_then(|slot| slot.as_mut())
464 }
465
466 fn color_attachments(&self) -> impl Iterator<Item = (AttachmentIndex, &ColorAttachment)> + '_ {
467 self.color
468 .iter()
469 .enumerate()
470 .filter_map(|(attachment_idx, slot)| {
471 Some((attachment_idx as AttachmentIndex, slot.as_ref()?))
472 })
473 }
474
475 fn depth_stencil_attachment(&self) -> Option<&DepthStencilAttachment> {
476 self.depth_stencil.as_ref()
477 }
478
479 fn depth_stencil_attachment_mut(&mut self) -> Option<&mut DepthStencilAttachment> {
480 self.depth_stencil.as_mut()
481 }
482
483 fn set_color_attachment(
484 &mut self,
485 attachment_idx: AttachmentIndex,
486 attachment: ColorAttachment,
487 ) {
488 let attachment_idx = attachment_idx as usize;
489
490 if self.color.len() <= attachment_idx {
491 self.color.resize(attachment_idx + 1, None);
492 }
493
494 #[cfg(feature = "checked")]
495 {
496 let existing_attachment = self.color[attachment_idx]
497 .as_ref()
498 .map(|&color| color.attachment);
499
500 assert!(
501 Attachment::are_compatible(existing_attachment, Some(attachment.attachment)),
502 "incompatible with existing attachment"
503 );
504 }
505
506 self.color[attachment_idx] = Some(attachment);
507 }
508
509 fn set_depth_stencil_attachment(&mut self, attachment: DepthStencilAttachment) {
510 #[cfg(feature = "checked")]
511 {
512 let existing_attachment = self
513 .depth_stencil
514 .as_ref()
515 .map(|&depth_stencil| depth_stencil.attachment);
516
517 assert!(
518 Attachment::are_compatible(existing_attachment, Some(attachment.attachment)),
519 "incompatible with existing attachment"
520 );
521 }
522
523 self.depth_stencil = Some(attachment);
524 }
525
526 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
527 for attachment in self.color.iter_mut().flatten() {
528 attachment.attachment.remap_nodes(node_map);
529
530 if let Some(resolve) = &mut attachment.resolve {
531 resolve.attachment.remap_nodes(node_map);
532 }
533 }
534
535 if let Some(attachment) = &mut self.depth_stencil {
536 attachment.attachment.remap_nodes(node_map);
537
538 if let Some(resolve) = &mut attachment.resolve {
539 resolve.attachment.remap_nodes(node_map);
540 }
541 }
542 }
543}
544
545#[derive(Clone, Copy, Debug)]
546struct ColorResolve {
547 attachment: Attachment,
548 src_attachment_idx: AttachmentIndex,
549}
550
551#[derive(Clone, Debug)]
552struct CommandData {
553 execs: Vec<Execution>,
554
555 #[cfg(debug_assertions)]
556 name: Option<String>,
557
558 stream_scope_id: Option<u64>,
559 tracking: CommandExecutions,
560}
561
562impl CommandData {
563 fn descriptor_pools_sizes(
564 &self,
565 ) -> impl Iterator<Item = impl Iterator<Item = (&vk::DescriptorType, &u32)>> {
566 self.execs.iter().flat_map(|exec| {
567 exec.pipeline.iter().map(move |pipeline| {
568 pipeline
569 .descriptor_info()
570 .pool_sizes
571 .iter()
572 .filter(move |(set, _)| !exec.descriptor_sets.contains_key(set))
573 .flat_map(|(_, pool)| pool.iter())
574 })
575 })
576 }
577
578 fn expect_first_exec(&self) -> &Execution {
579 self.execs.first().expect("missing command execution")
580 }
581
582 fn expect_last_exec(&self) -> &Execution {
586 self.execs.last().expect("missing command execution")
587 }
588
589 fn expect_last_exec_mut(&mut self) -> &mut Execution {
593 self.execs.last_mut().expect("missing command execution")
594 }
595
596 fn expect_last_pipeline(&self) -> &ExecutionPipeline {
597 self.expect_last_exec()
598 .pipeline
599 .as_ref()
600 .expect("missing command pipeline")
601 }
602
603 fn name(&self) -> &str {
604 const DEFAULT: &str = "command";
605
606 #[cfg(debug_assertions)]
607 {
608 self.name.as_deref().unwrap_or(DEFAULT)
609 }
610
611 #[cfg(not(debug_assertions))]
612 {
613 DEFAULT
614 }
615 }
616
617 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
618 for exec in &mut self.execs {
619 exec.remap_nodes(node_map);
620 }
621 }
622}
623
624impl Drop for CommandData {
625 fn drop(&mut self) {
626 self.tracking.signal_abandoned();
627 }
628}
629
630enum CommandFunction {
631 Once(CommandFnOnce),
632 Reusable(CommandFn),
633}
634
635impl CommandFunction {
636 fn is_reusable(&self) -> bool {
637 matches!(self, Self::Reusable(_))
638 }
639
640 fn record(self, cmd: CommandRef<'_>) -> Option<Self> {
641 match self {
642 Self::Once(func) => {
643 func(cmd);
644 None
645 }
646 Self::Reusable(func) => {
647 func(cmd);
648 Some(Self::Reusable(func))
649 }
650 }
651 }
652}
653
654impl Clone for CommandFunction {
655 fn clone(&self) -> Self {
656 match self {
657 Self::Once(_) => panic!("one-shot command callback cannot be cloned"),
658 Self::Reusable(func) => Self::Reusable(Arc::clone(func)),
659 }
660 }
661}
662
663#[derive(Clone, Copy, Debug)]
664struct DepthStencilAttachment {
665 attachment: Attachment,
666 load: LoadOp<vk::ClearDepthStencilValue>,
667 store: StoreOp,
668 resolve: Option<DepthStencilResolve>,
669 is_attachment: bool,
670}
671
672#[derive(Clone, Copy, Debug)]
673struct DepthStencilResolve {
674 attachment: Attachment,
675 dst_attachment_idx: AttachmentIndex,
676 depth_mode: Option<ResolveMode>,
677 stencil_mode: Option<ResolveMode>,
678}
679
680#[derive(Clone)]
681enum ExecutionAccess {
682 Building(ExecutionAccessBuilder),
683 Frozen(FrozenExecutionAccess),
684}
685
686impl ExecutionAccess {
687 fn contains(&self, node_idx: NodeIndex) -> bool {
688 match self {
689 Self::Building(builder) => builder.lookup.contains_key(&node_idx),
690 Self::Frozen(frozen) => frozen.lookup.contains_key(&node_idx),
691 }
692 }
693
694 fn freeze(&mut self) {
695 let Self::Building(builder) = mem::take(self) else {
696 return;
697 };
698
699 let ExecutionAccessBuilder { entries, lookup } = builder;
700 let entries = entries
701 .into_iter()
702 .map(|entry| NodeAccess {
703 node_idx: entry.node_idx,
704 accesses: entry.accesses.into_vec().into_boxed_slice(),
705 })
706 .collect();
707
708 *self = Self::Frozen(FrozenExecutionAccess { entries, lookup });
709 }
710
711 fn get_mut(&mut self, node_idx: &NodeIndex) -> Option<&mut [SubresourceAccess]> {
712 let Self::Building(builder) = self else {
713 panic!("execution accesses are frozen")
714 };
715
716 builder
717 .lookup
718 .get(node_idx)
719 .copied()
720 .map(|entry_idx| builder.entries[entry_idx].accesses.as_mut_slice())
721 }
722
723 fn iter(&self) -> ExecutionAccessIter<'_> {
724 match self {
725 Self::Building(builder) => ExecutionAccessIter::Building(builder.entries.iter()),
726 Self::Frozen(frozen) => ExecutionAccessIter::Frozen(frozen.entries.iter()),
727 }
728 }
729
730 fn push(&mut self, node_idx: NodeIndex, access: SubresourceAccess) {
731 let Self::Building(builder) = self else {
732 panic!("execution accesses are frozen")
733 };
734
735 let idx = *builder.lookup.entry(node_idx).or_insert_with(|| {
736 let idx = builder.entries.len();
737 builder.entries.push(NodeAccessBuilder {
738 node_idx,
739 accesses: Default::default(),
740 });
741
742 idx
743 });
744 builder.entries[idx].accesses.push(access);
745 }
746
747 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
748 match self {
749 Self::Building(builder) => {
750 for entry in &mut builder.entries {
751 entry.node_idx = node_map[entry.node_idx];
752 }
753
754 builder.lookup = builder
755 .entries
756 .iter()
757 .enumerate()
758 .map(|(idx, entry)| (entry.node_idx, idx))
759 .collect();
760 }
761 Self::Frozen(frozen) => {
762 for entry in frozen.entries.iter_mut() {
763 entry.node_idx = node_map[entry.node_idx];
764 }
765
766 frozen.lookup = frozen
767 .entries
768 .iter()
769 .enumerate()
770 .map(|(idx, entry)| (entry.node_idx, idx))
771 .collect();
772 }
773 }
774 }
775}
776
777impl Debug for ExecutionAccess {
778 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
779 match self {
780 Self::Building(builder) => builder.entries.fmt(f),
781 Self::Frozen(frozen) => frozen.entries.fmt(f),
782 }
783 }
784}
785
786impl Default for ExecutionAccess {
787 fn default() -> Self {
788 Self::Building(Default::default())
789 }
790}
791
792#[derive(Clone, Debug, Default)]
793struct ExecutionAccessBuilder {
794 entries: Vec<NodeAccessBuilder>,
795 lookup: HashMap<NodeIndex, usize>,
796}
797
798enum ExecutionAccessIter<'a> {
799 Building(Iter<'a, NodeAccessBuilder>),
800 Frozen(Iter<'a, NodeAccess>),
801}
802
803impl<'a> Iterator for ExecutionAccessIter<'a> {
804 type Item = (NodeIndex, &'a [SubresourceAccess]);
805
806 fn next(&mut self) -> Option<Self::Item> {
807 match self {
808 ExecutionAccessIter::Building(iter) => iter
809 .next()
810 .map(|entry| (entry.node_idx, entry.accesses.as_slice())),
811 ExecutionAccessIter::Frozen(iter) => iter
812 .next()
813 .map(|entry| (entry.node_idx, entry.accesses.as_ref())),
814 }
815 }
816
817 fn size_hint(&self) -> (usize, Option<usize>) {
818 let len = self.len();
819
820 (len, Some(len))
821 }
822}
823
824impl ExactSizeIterator for ExecutionAccessIter<'_> {
825 fn len(&self) -> usize {
826 match self {
827 ExecutionAccessIter::Building(iter) => iter.len(),
828 ExecutionAccessIter::Frozen(iter) => iter.len(),
829 }
830 }
831}
832
833#[derive(Clone, Default)]
834struct Execution {
835 accesses: ExecutionAccess,
836 attachments: ExecutionAttachmentMap,
837 bindings: BTreeMap<Binding, (NodeIndex, ViewInfo)>,
838 descriptor_sets: BTreeMap<u32, DescriptorSet>,
839
840 correlated_view_mask: u32,
841 depth_stencil: Option<DepthStencilInfo>,
842 render_area: Option<vk::Rect2D>,
843 view_mask: u32,
844
845 func: Option<CommandFunction>,
846 node_map: Option<Arc<[NodeIndex]>>,
847 pipeline: Option<ExecutionPipeline>,
848
849 #[cfg(feature = "checked")]
850 stream_graph_id: Option<GraphId>,
851}
852
853impl Execution {
854 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
855 let original_node_map = Arc::<[NodeIndex]>::from(node_map.to_vec());
856 self.accesses.remap_nodes(node_map);
857 self.attachments.remap_nodes(node_map);
858
859 self.bindings = mem::take(&mut self.bindings)
860 .into_iter()
861 .map(|(binding, (node_idx, view))| (binding, (node_map[node_idx], view)))
862 .collect();
863 self.node_map = Some(original_node_map);
864 }
865}
866
867impl Debug for Execution {
868 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
869 f.debug_struct("Execution")
872 .field("accesses", &self.accesses)
873 .field("attachments", &self.attachments)
874 .field("bindings", &self.bindings)
875 .field("descriptor_sets", &self.descriptor_sets)
876 .field("correlated_view_mask", &self.correlated_view_mask)
877 .field("depth_stencil", &self.depth_stencil)
878 .field("render_area", &self.render_area)
879 .field("view_mask", &self.view_mask)
880 .field("pipeline", &self.pipeline)
881 .finish()
882 }
883}
884
885#[derive(Clone, Debug)]
886enum ExecutionPipeline {
887 Compute(ComputePipeline),
888 Graphics(GraphicsPipeline),
889 RayTracing(RayTracingPipeline),
890}
891
892impl ExecutionPipeline {
893 fn as_graphics(&self) -> Option<&GraphicsPipeline> {
894 if let Self::Graphics(pipeline) = self {
895 Some(pipeline)
896 } else {
897 None
898 }
899 }
900
901 fn bind_point(&self) -> vk::PipelineBindPoint {
902 match self {
903 ExecutionPipeline::Compute(_) => vk::PipelineBindPoint::COMPUTE,
904 ExecutionPipeline::Graphics(_) => vk::PipelineBindPoint::GRAPHICS,
905 ExecutionPipeline::RayTracing(_) => vk::PipelineBindPoint::RAY_TRACING_KHR,
906 }
907 }
908
909 fn descriptor_bindings(&self) -> &DescriptorBindingMap {
910 match self {
911 ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_bindings,
912 ExecutionPipeline::Graphics(pipeline) => &pipeline.inner.descriptor_bindings,
913 ExecutionPipeline::RayTracing(pipeline) => &pipeline.inner.descriptor_bindings,
914 }
915 }
916
917 fn descriptor_info(&self) -> &PipelineDescriptorInfo {
918 match self {
919 ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_info,
920 ExecutionPipeline::Graphics(pipeline) => &pipeline.inner.descriptor_info,
921 ExecutionPipeline::RayTracing(pipeline) => &pipeline.inner.descriptor_info,
922 }
923 }
924
925 fn expect_compute(&self) -> &ComputePipeline {
926 if let Self::Compute(pipeline) = self {
927 pipeline
928 } else {
929 panic!("missing compute pipeline")
930 }
931 }
932
933 fn expect_graphics(&self) -> &GraphicsPipeline {
934 self.as_graphics().expect("missing graphics pipeline")
935 }
936
937 fn expect_ray_tracing(&self) -> &RayTracingPipeline {
938 if let Self::RayTracing(pipeline) = self {
939 pipeline
940 } else {
941 panic!("missing ray tracing pipeline")
942 }
943 }
944
945 fn layout(&self) -> vk::PipelineLayout {
946 match self {
947 ExecutionPipeline::Compute(pipeline) => pipeline.inner.layout,
948 ExecutionPipeline::Graphics(pipeline) => pipeline.inner.layout,
949 ExecutionPipeline::RayTracing(pipeline) => pipeline.inner.layout,
950 }
951 }
952}
953
954#[derive(Clone, Debug)]
955struct FrozenExecutionAccess {
956 entries: Box<[NodeAccess]>,
957 lookup: HashMap<NodeIndex, usize>,
958}
959
960#[derive(Debug)]
969pub struct Graph {
970 cmds: Vec<CommandData>,
971 resources: ResourceMap,
972 timestamp_queries: Option<Vec<Option<TimestampQueryData>>>,
973
974 #[cfg(feature = "checked")]
975 graph_id: GraphId,
976}
977
978pub struct GraphBuilder {
980 graph: Graph,
981}
982
983impl GraphBuilder {
984 pub fn new() -> Self {
986 Self {
987 graph: Graph::new(),
988 }
989 }
990
991 pub fn build(self) -> Graph {
993 self.graph
994 }
995
996 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
998 where
999 R: Resource,
1000 {
1001 self.graph.bind_resource(resource)
1002 }
1003
1004 pub fn blit_image(
1006 mut self,
1007 src: impl Into<AnyImageNode>,
1008 dst: impl Into<AnyImageNode>,
1009 filter: vk::Filter,
1010 ) -> Self {
1011 self.graph.blit_image(src, dst, filter);
1012 self
1013 }
1014
1015 pub fn clear_color_image(
1017 mut self,
1018 image: impl Into<AnyImageNode>,
1019 color: impl Into<ClearColorValue>,
1020 ) -> Self {
1021 self.graph.clear_color_image(image, color);
1022 self
1023 }
1024
1025 pub fn clear_depth_stencil_image(
1027 mut self,
1028 image: impl Into<AnyImageNode>,
1029 depth: f32,
1030 stencil: u32,
1031 ) -> Self {
1032 self.graph.clear_depth_stencil_image(image, depth, stencil);
1033 self
1034 }
1035
1036 pub fn copy_buffer(
1038 mut self,
1039 src: impl Into<AnyBufferNode>,
1040 dst: impl Into<AnyBufferNode>,
1041 ) -> Self {
1042 self.graph.copy_buffer(src, dst);
1043 self
1044 }
1045
1046 pub fn copy_buffer_to_image(
1048 mut self,
1049 src: impl Into<AnyBufferNode>,
1050 dst: impl Into<AnyImageNode>,
1051 ) -> Self {
1052 self.graph.copy_buffer_to_image(src, dst);
1053 self
1054 }
1055
1056 pub fn copy_image(
1058 mut self,
1059 src: impl Into<AnyImageNode>,
1060 dst: impl Into<AnyImageNode>,
1061 ) -> Self {
1062 self.graph.copy_image(src, dst);
1063 self
1064 }
1065
1066 pub fn copy_image_to_buffer(
1068 mut self,
1069 src: impl Into<AnyImageNode>,
1070 dst: impl Into<AnyBufferNode>,
1071 ) -> Self {
1072 self.graph.copy_image_to_buffer(src, dst);
1073 self
1074 }
1075
1076 pub fn fill_buffer(
1078 mut self,
1079 buffer: impl Into<AnyBufferNode>,
1080 region: Range<vk::DeviceSize>,
1081 data: u32,
1082 ) -> Self {
1083 self.graph.fill_buffer(buffer, region, data);
1084 self
1085 }
1086
1087 pub fn update_buffer(
1089 mut self,
1090 buffer: impl Into<AnyBufferNode>,
1091 offset: vk::DeviceSize,
1092 data: impl AsRef<[u8]> + 'static + Send,
1093 ) -> Self {
1094 self.graph.update_buffer(buffer, offset, data);
1095 self
1096 }
1097}
1098
1099impl Default for GraphBuilder {
1100 fn default() -> Self {
1101 Self::new()
1102 }
1103}
1104
1105impl Default for Graph {
1106 fn default() -> Self {
1107 Self {
1108 cmds: Default::default(),
1109 resources: Default::default(),
1110 timestamp_queries: Default::default(),
1111
1112 #[cfg(feature = "checked")]
1113 graph_id: GraphId::next(),
1114 }
1115 }
1116}
1117
1118impl Graph {
1119 pub fn new() -> Self {
1121 Self::default()
1122 }
1123
1124 pub fn builder() -> GraphBuilder {
1126 GraphBuilder::new()
1127 }
1128
1129 pub fn into_builder(self) -> GraphBuilder {
1131 GraphBuilder { graph: self }
1132 }
1133
1134 pub(crate) fn assert_node_owner<N>(&self, _resource_node: &N)
1135 where
1136 N: Node,
1137 {
1138 #[cfg(feature = "checked")]
1139 _resource_node.assert_owner(self.graph_id);
1140 }
1141
1142 #[cfg(feature = "checked")]
1143 pub(crate) fn graph_id(&self) -> GraphId {
1144 self.graph_id
1145 }
1146
1147 pub fn begin_cmd(&mut self) -> Command<'_> {
1149 Command::new(self)
1150 }
1151
1152 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
1157 where
1158 R: Resource,
1159 {
1160 resource.bind_graph(self)
1161 }
1162
1163 pub(crate) fn bind_stream_arg_resource(&mut self, resource: AnyResource) -> NodeIndex {
1164 self.resources.bind(resource)
1165 }
1166
1167 pub fn blit_image(
1174 &mut self,
1175 src: impl Into<AnyImageNode>,
1176 dst: impl Into<AnyImageNode>,
1177 filter: vk::Filter,
1178 ) -> &mut Self {
1179 let src = src.into();
1180 let src_info = self.resources[src.index()].expect_image_info();
1181
1182 let dst = dst.into();
1183 let dst_info = self.resources[dst.index()].expect_image_info();
1184
1185 self.begin_cmd()
1186 .debug_name("blit image")
1187 .blit_image(
1188 src,
1189 dst,
1190 filter,
1191 [vk::ImageBlit {
1192 src_subresource: vk::ImageSubresourceLayers {
1193 aspect_mask: format_aspect_mask(src_info.format),
1194 mip_level: 0,
1195 base_array_layer: 0,
1196 layer_count: 1,
1197 },
1198 src_offsets: [
1199 vk::Offset3D { x: 0, y: 0, z: 0 },
1200 vk::Offset3D {
1201 x: src_info.width as _,
1202 y: src_info.height as _,
1203 z: src_info.depth as _,
1204 },
1205 ],
1206 dst_subresource: vk::ImageSubresourceLayers {
1207 aspect_mask: format_aspect_mask(dst_info.format),
1208 mip_level: 0,
1209 base_array_layer: 0,
1210 layer_count: 1,
1211 },
1212 dst_offsets: [
1213 vk::Offset3D { x: 0, y: 0, z: 0 },
1214 vk::Offset3D {
1215 x: dst_info.width as _,
1216 y: dst_info.height as _,
1217 z: dst_info.depth as _,
1218 },
1219 ],
1220 }],
1221 )
1222 .end_cmd()
1223 }
1224
1225 #[profiling::function]
1232 #[doc(hidden)]
1233 #[deprecated(note = "use Graph::begin_cmd().blit_image(...).end_cmd() for explicit regions")]
1234 pub fn blit_image_region(
1235 &mut self,
1236 src: impl Into<AnyImageNode>,
1237 dst: impl Into<AnyImageNode>,
1238 filter: vk::Filter,
1239 regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
1240 ) -> &mut Self {
1241 self.begin_cmd()
1242 .debug_name("blit image")
1243 .blit_image(src, dst, filter, regions)
1244 .end_cmd()
1245 }
1246
1247 #[profiling::function]
1254 pub fn clear_color_image(
1255 &mut self,
1256 image: impl Into<AnyImageNode>,
1257 color: impl Into<ClearColorValue>,
1258 ) -> &mut Self {
1259 self.begin_cmd()
1260 .debug_name("clear color")
1261 .clear_color_image(image, color)
1262 .end_cmd()
1263 }
1264
1265 #[profiling::function]
1272 pub fn clear_depth_stencil_image(
1273 &mut self,
1274 image: impl Into<AnyImageNode>,
1275 depth: f32,
1276 stencil: u32,
1277 ) -> &mut Self {
1278 self.begin_cmd()
1279 .debug_name("clear depth/stencil")
1280 .clear_depth_stencil_image(image, depth, stencil)
1281 .end_cmd()
1282 }
1283
1284 pub fn copy_buffer(
1291 &mut self,
1292 src: impl Into<AnyBufferNode>,
1293 dst: impl Into<AnyBufferNode>,
1294 ) -> &mut Self {
1295 let src = src.into();
1296 let dst = dst.into();
1297 let src_info = self.resources[src.index()].expect_buffer_info();
1298 let dst_info = self.resources[dst.index()].expect_buffer_info();
1299
1300 self.begin_cmd()
1301 .debug_name("copy buffer")
1302 .copy_buffer(
1303 src,
1304 dst,
1305 [vk::BufferCopy {
1306 src_offset: 0,
1307 dst_offset: 0,
1308 size: src_info.size.min(dst_info.size),
1309 }],
1310 )
1311 .end_cmd()
1312 }
1313
1314 #[profiling::function]
1321 #[doc(hidden)]
1322 #[deprecated(note = "use Graph::begin_cmd().copy_buffer(...).end_cmd() for explicit regions")]
1323 pub fn copy_buffer_region(
1324 &mut self,
1325 src: impl Into<AnyBufferNode>,
1326 dst: impl Into<AnyBufferNode>,
1327 regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
1328 ) -> &mut Self {
1329 self.begin_cmd()
1330 .debug_name("copy buffer")
1331 .copy_buffer(src, dst, regions)
1332 .end_cmd()
1333 }
1334
1335 pub fn copy_buffer_to_image(
1341 &mut self,
1342 src: impl Into<AnyBufferNode>,
1343 dst: impl Into<AnyImageNode>,
1344 ) -> &mut Self {
1345 let dst = dst.into();
1346 let dst_info = self.resources[dst.index()].expect_image_info();
1347
1348 self.begin_cmd()
1349 .debug_name("copy buffer to image")
1350 .copy_buffer_to_image(
1351 src,
1352 dst,
1353 [vk::BufferImageCopy {
1354 buffer_offset: 0,
1355 buffer_row_length: dst_info.width,
1356 buffer_image_height: dst_info.height,
1357 image_subresource: vk::ImageSubresourceLayers {
1358 aspect_mask: format_aspect_mask(dst_info.format),
1359 mip_level: 0,
1360 base_array_layer: 0,
1361 layer_count: 1,
1362 },
1363 image_offset: Default::default(),
1364 image_extent: vk::Extent3D {
1365 depth: dst_info.depth,
1366 height: dst_info.height,
1367 width: dst_info.width,
1368 },
1369 }],
1370 )
1371 .end_cmd()
1372 }
1373
1374 #[profiling::function]
1381 #[doc(hidden)]
1382 #[deprecated(
1383 note = "use Graph::begin_cmd().copy_buffer_to_image(...).end_cmd() for explicit regions"
1384 )]
1385 pub fn copy_buffer_to_image_region(
1386 &mut self,
1387 src: impl Into<AnyBufferNode>,
1388 dst: impl Into<AnyImageNode>,
1389 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1390 ) -> &mut Self {
1391 self.begin_cmd()
1392 .debug_name("copy buffer to image")
1393 .copy_buffer_to_image(src, dst, regions)
1394 .end_cmd()
1395 }
1396
1397 pub fn copy_image(
1404 &mut self,
1405 src: impl Into<AnyImageNode>,
1406 dst: impl Into<AnyImageNode>,
1407 ) -> &mut Self {
1408 let src = src.into();
1409 let src_info = self.resources[src.index()].expect_image_info();
1410
1411 let dst = dst.into();
1412 let dst_info = self.resources[dst.index()].expect_image_info();
1413
1414 self.begin_cmd()
1415 .debug_name("copy image")
1416 .copy_image(
1417 src,
1418 dst,
1419 [vk::ImageCopy {
1420 src_subresource: vk::ImageSubresourceLayers {
1421 aspect_mask: format_aspect_mask(src_info.format),
1422 mip_level: 0,
1423 base_array_layer: 0,
1424 layer_count: src_info.array_layer_count,
1425 },
1426 src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1427 dst_subresource: vk::ImageSubresourceLayers {
1428 aspect_mask: format_aspect_mask(dst_info.format),
1429 mip_level: 0,
1430 base_array_layer: 0,
1431 layer_count: src_info.array_layer_count,
1432 },
1433 dst_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1434 extent: vk::Extent3D {
1435 depth: src_info.depth.clamp(1, dst_info.depth),
1436 height: src_info.height.clamp(1, dst_info.height),
1437 width: src_info.width.min(dst_info.width),
1438 },
1439 }],
1440 )
1441 .end_cmd()
1442 }
1443
1444 #[profiling::function]
1451 #[doc(hidden)]
1452 #[deprecated(note = "use Graph::begin_cmd().copy_image(...).end_cmd() for explicit regions")]
1453 pub fn copy_image_region(
1454 &mut self,
1455 src: impl Into<AnyImageNode>,
1456 dst: impl Into<AnyImageNode>,
1457 regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
1458 ) -> &mut Self {
1459 self.begin_cmd()
1460 .debug_name("copy image")
1461 .copy_image(src, dst, regions)
1462 .end_cmd()
1463 }
1464
1465 pub fn copy_image_to_buffer(
1471 &mut self,
1472 src: impl Into<AnyImageNode>,
1473 dst: impl Into<AnyBufferNode>,
1474 ) -> &mut Self {
1475 let src = src.into();
1476 let dst = dst.into();
1477
1478 let src_info = self.resources[src.index()].expect_image_info();
1479
1480 self.begin_cmd()
1481 .debug_name("copy image to buffer")
1482 .copy_image_to_buffer(
1483 src,
1484 dst,
1485 [vk::BufferImageCopy {
1486 buffer_offset: 0,
1487 buffer_row_length: src_info.width,
1488 buffer_image_height: src_info.height,
1489 image_subresource: vk::ImageSubresourceLayers {
1490 aspect_mask: format_aspect_mask(src_info.format),
1491 mip_level: 0,
1492 base_array_layer: 0,
1493 layer_count: 1,
1494 },
1495 image_offset: Default::default(),
1496 image_extent: vk::Extent3D {
1497 depth: src_info.depth,
1498 height: src_info.height,
1499 width: src_info.width,
1500 },
1501 }],
1502 )
1503 .end_cmd()
1504 }
1505
1506 #[profiling::function]
1513 #[doc(hidden)]
1514 #[deprecated(
1515 note = "use Graph::begin_cmd().copy_image_to_buffer(...).end_cmd() for explicit regions"
1516 )]
1517 pub fn copy_image_to_buffer_region(
1518 &mut self,
1519 src: impl Into<AnyImageNode>,
1520 dst: impl Into<AnyBufferNode>,
1521 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1522 ) -> &mut Self {
1523 self.begin_cmd()
1524 .debug_name("copy image to buffer")
1525 .copy_image_to_buffer(src, dst, regions)
1526 .end_cmd()
1527 }
1528
1529 pub fn fill_buffer(
1535 &mut self,
1536 buffer: impl Into<AnyBufferNode>,
1537 region: Range<vk::DeviceSize>,
1538 data: u32,
1539 ) -> &mut Self {
1540 self.begin_cmd()
1541 .debug_name("fill buffer")
1542 .fill_buffer(buffer, region, data)
1543 .end_cmd()
1544 }
1545
1546 #[profiling::function]
1548 fn first_node_access_pass_index(&self, resource_node: impl Node) -> Option<usize> {
1549 self.assert_node_owner(&resource_node);
1550
1551 let node_idx = resource_node.index();
1552
1553 for (pass_idx, pass) in self.cmds.iter().enumerate() {
1554 for exec in pass.execs.iter() {
1555 if exec.accesses.contains(node_idx) {
1556 return Some(pass_idx);
1557 }
1558 }
1559 }
1560
1561 None
1562 }
1563
1564 #[profiling::function]
1567 pub fn finalize(mut self) -> Submission {
1568 thread_local! {
1569 static TLS: RefCell<Vec<usize>> = Default::default();
1570 }
1571
1572 TLS.with_borrow_mut(|tls| {
1573 let old_cmd_len = self.cmds.len();
1574
1575 tls.clear();
1576 tls.resize(old_cmd_len + 1, 0);
1577
1578 let mut old_cmd_idx = 0;
1579 let mut new_cmd_idx = 0;
1580
1581 self.cmds.retain_mut(|cmd| {
1582 tls[old_cmd_idx] = new_cmd_idx;
1583 old_cmd_idx += 1;
1584
1585 debug_assert!(cmd.expect_last_exec().func.is_none());
1587
1588 cmd.execs.pop();
1589
1590 for exec in &mut cmd.execs {
1591 exec.accesses.freeze();
1592 }
1593
1594 if cmd.execs.is_empty() {
1595 false
1596 } else {
1597 new_cmd_idx += 1;
1598 true
1599 }
1600 });
1601
1602 tls[old_cmd_len] = new_cmd_idx;
1603
1604 if let Some(timestamp_queries) = &mut self.timestamp_queries {
1605 for query in timestamp_queries.iter_mut().flatten() {
1606 query.command_idx = tls[query.command_idx];
1607 }
1608 }
1609 });
1610
1611 if let Some(timestamp_queries) = &self.timestamp_queries {
1612 stat::sample_timestamp_queries_len(timestamp_queries.iter().flatten().count());
1613 }
1614
1615 Submission::new(self)
1616 }
1617
1618 pub fn resource<N>(&self, resource_node: N) -> &N::Resource
1635 where
1636 N: Node,
1637 {
1638 self.assert_node_owner(&resource_node);
1639 resource_node.borrow(&self.resources)
1640 }
1641
1642 #[profiling::function]
1651 pub fn update_buffer(
1652 &mut self,
1653 buffer: impl Into<AnyBufferNode>,
1654 offset: vk::DeviceSize,
1655 data: impl AsRef<[u8]> + 'static + Send,
1656 ) -> &mut Self {
1657 debug_assert!(data.as_ref().len() <= 64 * 1024);
1658
1659 let buffer = buffer.into();
1660 let data_end = offset + data.as_ref().len() as vk::DeviceSize;
1661
1662 #[cfg(feature = "checked")]
1663 {
1664 assert!(
1665 data.as_ref().len() <= 64 * 1024,
1666 "data length ({}) exceeds vkCmdUpdateBuffer limit (65536)",
1667 data.as_ref().len()
1668 );
1669
1670 let buffer_info = self.resources[buffer.index()].expect_buffer_info();
1671
1672 assert!(
1673 data_end <= buffer_info.size,
1674 "data range end ({data_end}) exceeds buffer size ({})",
1675 buffer_info.size
1676 );
1677 }
1678
1679 let data = Arc::<[u8]>::from(data.as_ref());
1680
1681 self.begin_cmd()
1682 .debug_name("update buffer")
1683 .subresource_access(buffer, offset..data_end, AccessType::TransferWrite)
1684 .record_stream(move |cmd| {
1685 let buffer = cmd.resource(buffer);
1686
1687 unsafe {
1688 cmd.device
1689 .cmd_update_buffer(cmd.handle, buffer.handle, offset, &data);
1690 }
1691 })
1692 .end_cmd()
1693 }
1694
1695 pub fn write_timestamp(&mut self) -> TimestampQuery {
1708 self.write_timestamp_at(self.cmds.len(), 0, TimestampQueryPlacement::BeforeExec)
1709 }
1710
1711 pub(crate) fn write_timestamp_at(
1712 &mut self,
1713 command_idx: usize,
1714 exec_idx: usize,
1715 placement: TimestampQueryPlacement,
1716 ) -> TimestampQuery {
1717 let timestamp_queries = self.timestamp_queries.get_or_insert_with(|| {
1718 Vec::with_capacity(stat::thread_local_timestamp_queries_capacity_hint())
1719 });
1720 let query = TimestampQuery {
1721 index: timestamp_queries.len() as u32,
1722 #[cfg(feature = "checked")]
1723 graph_id: self.graph_id,
1724 };
1725
1726 timestamp_queries.push(Some(TimestampQueryData {
1727 command_idx,
1728 exec_idx,
1729 placement,
1730 pool_query: None,
1731 query,
1732 }));
1733
1734 query
1735 }
1736}
1737
1738#[derive(Clone, Copy, Debug)]
1743pub enum LoadOp<T> {
1744 Clear(T),
1749
1750 DontCare,
1752
1753 Load,
1755}
1756
1757#[allow(private_bounds)]
1763pub trait Node: private::NodeSealed {
1764 type Resource;
1766
1767 type SyncInfo;
1769
1770 #[doc(hidden)]
1771 fn index(&self) -> usize;
1772}
1773
1774#[derive(Clone, Debug)]
1775struct NodeAccess {
1776 node_idx: NodeIndex,
1777 accesses: Box<[SubresourceAccess]>,
1778}
1779
1780#[derive(Clone, Debug)]
1781struct NodeAccessBuilder {
1782 node_idx: NodeIndex,
1783 accesses: SmallVec<[SubresourceAccess; 2]>,
1784}
1785
1786mod private {
1787 use super::{AnyResource, Node};
1788
1789 #[cfg(feature = "checked")]
1790 use super::GraphId;
1791
1792 pub(crate) trait NodeSealed: Sized {
1794 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource
1795 where
1796 Self: Node;
1797
1798 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource
1799 where
1800 Self: Node,
1801 {
1802 debug_assert_eq!(self.index(), index);
1803 self.borrow(resources)
1804 }
1805
1806 #[cfg(feature = "checked")]
1807 fn assert_owner(&self, _graph_id: GraphId) {}
1808 }
1809
1810 pub(crate) trait ResourceSealed {}
1812}
1813
1814#[allow(private_bounds)]
1821pub trait Resource: private::ResourceSealed {
1822 type Node;
1824
1825 #[doc(hidden)]
1826 fn bind_graph(self, _: &mut Graph) -> Self::Node;
1827}
1828
1829impl private::ResourceSealed for SwapchainImage {}
1830
1831impl Resource for SwapchainImage {
1832 type Node = SwapchainImageNode;
1833
1834 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1835 let node = Self::Node::new(
1836 graph.resources.len(),
1837 #[cfg(feature = "checked")]
1838 graph.graph_id,
1839 );
1840
1841 let resource = AnyResource::SwapchainImage(Box::new(self));
1844 graph.resources.bind(resource);
1845
1846 node
1847 }
1848}
1849
1850macro_rules! resource {
1851 ($name:ident) => {
1852 paste::paste! {
1853 impl private::ResourceSealed for $name {}
1854 impl private::ResourceSealed for Arc<$name> {}
1855 impl<'a> private::ResourceSealed for &'a Arc<$name> {}
1856 impl private::ResourceSealed for Lease<$name> {}
1857 impl private::ResourceSealed for Arc<Lease<$name>> {}
1858 impl<'a> private::ResourceSealed for &'a Arc<Lease<$name>> {}
1859
1860 impl Resource for $name {
1861 type Node = [<$name Node>];
1862
1863 #[profiling::function]
1864 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1865 Arc::new(self).bind_graph(graph)
1869 }
1870 }
1871
1872 impl Resource for Arc<$name> {
1873 type Node = [<$name Node>];
1874
1875 #[profiling::function]
1876 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1877 Self::Node::new(
1881 graph.resources.bind_shared(self),
1882 #[cfg(feature = "checked")]
1883 graph.graph_id,
1884 )
1885 }
1886 }
1887
1888 impl<'a> Resource for &'a Arc<$name> {
1889 type Node = [<$name Node>];
1890
1891 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1892 Arc::clone(self).bind_graph(graph)
1895 }
1896 }
1897
1898 impl Resource for Lease<$name> {
1899 type Node = [<$name LeaseNode>];
1900
1901 #[profiling::function]
1902 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1903 Arc::new(self).bind_graph(graph)
1907 }
1908 }
1909
1910 impl Resource for Arc<Lease<$name>> {
1911 type Node = [<$name LeaseNode>];
1912
1913 #[profiling::function]
1914 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1915 Self::Node::new(
1920 graph.resources.bind_shared(self),
1921 #[cfg(feature = "checked")]
1922 graph.graph_id,
1923 )
1924 }
1925 }
1926
1927 impl<'a> Resource for &'a Arc<Lease<$name>> {
1928 type Node = [<$name LeaseNode>];
1929
1930 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1931 Arc::clone(self).bind_graph(graph)
1935 }
1936 }
1937 }
1938 };
1939}
1940
1941resource!(AccelerationStructure);
1942resource!(Image);
1943resource!(Buffer);
1944
1945#[derive(Debug, Default)]
1946struct ResourceMap {
1947 addr_index: HashMap<usize, NodeIndex>,
1948 resources: Vec<AnyResource>,
1949}
1950
1951impl ResourceMap {
1952 pub(crate) fn from_resources(resources: Vec<AnyResource>) -> Self {
1953 Self {
1954 addr_index: HashMap::new(),
1955 resources,
1956 }
1957 }
1958
1959 fn bind(&mut self, resource: AnyResource) -> NodeIndex {
1960 let node_idx = self.resources.len();
1961 self.resources.push(resource);
1962
1963 node_idx
1964 }
1965
1966 fn bind_shared<T>(&mut self, resource: Arc<T>) -> NodeIndex
1967 where
1968 Arc<T>: Into<AnyResource>,
1969 {
1970 let addr = Arc::as_ptr(&resource) as usize;
1971
1972 *self.addr_index.entry(addr).or_insert_with(|| {
1973 let node_idx = self.resources.len();
1974 self.resources.push(resource.into());
1975
1976 node_idx
1977 })
1978 }
1979}
1980
1981impl Deref for ResourceMap {
1982 type Target = [AnyResource];
1983
1984 fn deref(&self) -> &Self::Target {
1985 &self.resources
1986 }
1987}
1988
1989impl DerefMut for ResourceMap {
1990 fn deref_mut(&mut self) -> &mut Self::Target {
1991 &mut self.resources
1992 }
1993}
1994
1995#[derive(Clone, Copy, Debug, PartialEq)]
2000pub enum StoreOp {
2001 DontCare,
2003
2004 Store,
2006}
2007
2008#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2011pub struct TimestampQuery {
2012 index: u32,
2013
2014 #[cfg(feature = "checked")]
2015 graph_id: GraphId,
2016}
2017
2018impl TimestampQuery {
2019 pub(crate) fn index(self) -> u32 {
2020 self.index
2021 }
2022
2023 #[cfg(feature = "checked")]
2024 pub(crate) fn graph_id(self) -> GraphId {
2025 self.graph_id
2026 }
2027}
2028
2029#[derive(Clone, Copy, Debug)]
2030struct TimestampQueryData {
2031 command_idx: usize,
2032 exec_idx: usize,
2033 placement: TimestampQueryPlacement,
2034 pool_query: Option<u32>,
2035 query: TimestampQuery,
2036}
2037
2038#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
2039enum TimestampQueryPlacement {
2040 BeforeExec,
2041 AfterExec,
2042}
2043
2044#[doc(hidden)]
2045pub mod stat {
2046 use std::cell::RefCell;
2047
2048 const WINDOW_SIZE: usize = 3;
2049
2050 thread_local! {
2051 static TIMESTAMP_QUERIES_CAPACITY: RefCell<([usize; WINDOW_SIZE], usize)> = const {
2052 RefCell::new(([16; WINDOW_SIZE], 0))
2053 };
2054 }
2055
2056 pub(crate) fn sample_timestamp_queries_len(len: usize) {
2057 TIMESTAMP_QUERIES_CAPACITY.with_borrow_mut(|(capacities, index)| {
2058 capacities[*index] = len;
2059 *index += 1;
2060 *index %= WINDOW_SIZE;
2061 });
2062 }
2063
2064 pub fn set_thread_local_timestamp_queries_capacity_hint(capacity: usize) {
2065 TIMESTAMP_QUERIES_CAPACITY.with_borrow_mut(|(capacities, _)| {
2066 for val in capacities.iter_mut() {
2067 *val = capacity;
2068 }
2069 });
2070 }
2071
2072 pub(crate) fn thread_local_timestamp_queries_capacity_hint() -> usize {
2073 TIMESTAMP_QUERIES_CAPACITY
2074 .with_borrow(|(capacities, _)| capacities.iter().sum::<usize>() / WINDOW_SIZE)
2075 }
2076}
2077
2078#[cfg(test)]
2079mod test {
2080 use std::sync::Arc;
2081
2082 use ash::vk;
2083
2084 use super::{
2085 AnyResource, CommandExecutionAbandoned, CommandExecutions, Graph, Node, ResourceMap,
2086 };
2087 use crate::driver::{
2088 DriverError,
2089 accel_struct::{AccelerationStructure, AccelerationStructureInfo},
2090 buffer::{Buffer, BufferInfo},
2091 device::{Device, DeviceInfo},
2092 image::{Image, ImageInfo},
2093 swapchain::SwapchainImage,
2094 };
2095 use crate::pool::{Pool, hash::HashPool};
2096
2097 #[test]
2098 fn command_execution_starts_pending() {
2099 let mut graph = Graph::new();
2100 let mut cmd = graph.begin_cmd();
2101 let execution = cmd.track_execution();
2102
2103 assert_eq!(execution.has_executed(), Ok(false));
2104 }
2105
2106 #[test]
2107 fn command_execution_is_abandoned_when_graph_drops() {
2108 let execution = {
2109 let mut graph = Graph::new();
2110 let mut cmd = graph.begin_cmd();
2111
2112 cmd.track_execution()
2113 };
2114
2115 assert_eq!(execution.has_executed(), Err(CommandExecutionAbandoned));
2116 }
2117
2118 #[test]
2119 fn command_executions_track_multiple_handles() {
2120 let mut executions = CommandExecutions::default();
2121 let first = executions.track();
2122 let second = executions.track();
2123
2124 executions.signal_executed();
2125
2126 assert_eq!(first.has_executed(), Ok(true));
2127 assert_eq!(second.has_executed(), Ok(true));
2128 }
2129
2130 #[test]
2131 fn command_executions_extend_preserves_both_sides() {
2132 let mut lhs = CommandExecutions::default();
2133 let first = lhs.track();
2134 let mut rhs = CommandExecutions::default();
2135 let second = rhs.track();
2136
2137 lhs.extend(rhs);
2138 lhs.signal_executed();
2139
2140 assert_eq!(first.has_executed(), Ok(true));
2141 assert_eq!(second.has_executed(), Ok(true));
2142 }
2143
2144 #[test]
2145 fn command_execution_stays_executed_after_tracker_drops() {
2146 let execution = {
2147 let mut executions = CommandExecutions::default();
2148 let execution = executions.track();
2149
2150 executions.signal_executed();
2151
2152 execution
2153 };
2154
2155 assert_eq!(execution.has_executed(), Ok(true));
2156 }
2157
2158 #[test]
2159 fn command_execution_abandoned_converts_to_driver_error() {
2160 let error = DriverError::from(CommandExecutionAbandoned);
2161
2162 assert!(matches!(error, DriverError::InvalidData));
2163 }
2164
2165 mod integration {
2166 use super::*;
2167
2168 fn test_device() -> Result<Device, DriverError> {
2169 Device::create(DeviceInfo::default())
2170 }
2171
2172 mod resource_map {
2173 use super::*;
2174
2175 #[test]
2176 #[ignore = "requires Vulkan device"]
2177 fn bind_assigns_a_new_node_index_every_time() -> Result<(), DriverError> {
2178 let device = test_device()?;
2179 let buffer = Arc::new(Buffer::create(
2180 &device,
2181 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2182 )?);
2183 let image = Arc::new(Image::create(
2184 &device,
2185 ImageInfo::image_2d(
2186 1,
2187 1,
2188 vk::Format::R8G8B8A8_UNORM,
2189 vk::ImageUsageFlags::SAMPLED,
2190 ),
2191 )?);
2192 let mut resources = ResourceMap::default();
2193
2194 assert_eq!(resources.bind(AnyResource::from(buffer)), 0);
2195 assert_eq!(resources.bind(AnyResource::from(image)), 1);
2196 assert_eq!(resources.len(), 2);
2197
2198 Ok(())
2199 }
2200
2201 #[test]
2202 #[ignore = "requires Vulkan device"]
2203 fn bind_shared_reuses_the_existing_node_index_for_the_same_address()
2204 -> Result<(), DriverError> {
2205 let device = test_device()?;
2206 let buffer = Arc::new(Buffer::create(
2207 &device,
2208 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2209 )?);
2210 let mut resources = ResourceMap::default();
2211
2212 assert_eq!(resources.bind_shared(Arc::clone(&buffer)), 0);
2213 assert_eq!(resources.bind_shared(buffer), 0);
2214 assert_eq!(resources.len(), 1);
2215
2216 Ok(())
2217 }
2218
2219 #[test]
2220 #[ignore = "requires Vulkan device"]
2221 fn bind_shared_creates_distinct_node_indices_for_different_addresses()
2222 -> Result<(), DriverError> {
2223 let device = test_device()?;
2224 let buffer = Arc::new(Buffer::create(
2225 &device,
2226 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2227 )?);
2228 let image = Arc::new(Image::create(
2229 &device,
2230 ImageInfo::image_2d(
2231 1,
2232 1,
2233 vk::Format::R8G8B8A8_UNORM,
2234 vk::ImageUsageFlags::SAMPLED,
2235 ),
2236 )?);
2237 let mut resources = ResourceMap::default();
2238
2239 assert_eq!(resources.bind_shared(buffer), 0);
2240 assert_eq!(resources.bind_shared(image), 1);
2241 assert_eq!(resources.len(), 2);
2242
2243 Ok(())
2244 }
2245
2246 #[test]
2247 #[ignore = "requires Vulkan device"]
2248 fn graph_bind_fuzzes_all_resource_paths() -> Result<(), DriverError> {
2249 #[derive(Clone, Copy)]
2250 enum ResourceKind {
2251 OwnedBuffer,
2252 SharedBuffer,
2253 OwnedBufferLease,
2254 SharedBufferLease,
2255 OwnedImage,
2256 SharedImage,
2257 OwnedImageLease,
2258 SharedImageLease,
2259 SwapchainImage,
2260 OwnedAccelerationStructure,
2261 SharedAccelerationStructure,
2262 OwnedAccelerationStructureLease,
2263 SharedAccelerationStructureLease,
2264 }
2265
2266 struct SharedNodes<T> {
2267 values: Vec<(Arc<T>, usize)>,
2268 }
2269
2270 impl<T> Default for SharedNodes<T> {
2271 fn default() -> Self {
2272 Self { values: Vec::new() }
2273 }
2274 }
2275
2276 impl<T> SharedNodes<T> {
2277 fn get(&self, idx: usize) -> Option<(Arc<T>, usize)> {
2278 self.values
2279 .get(idx)
2280 .map(|(resource, node_idx)| (Arc::clone(resource), *node_idx))
2281 }
2282
2283 fn push(&mut self, resource: Arc<T>, node_idx: usize) {
2284 self.values.push((resource, node_idx));
2285 }
2286
2287 fn len(&self) -> usize {
2288 self.values.len()
2289 }
2290 }
2291
2292 fn next_rand(state: &mut u64) -> u64 {
2293 *state ^= *state << 13;
2294 *state ^= *state >> 7;
2295 *state ^= *state << 17;
2296 *state
2297 }
2298
2299 let device = test_device()?;
2300 let mut pool = HashPool::new(&device);
2301 let mut graph = Graph::new();
2302
2303 let mut rand_state = 0x5eed_u64;
2304 let mut shared_buffers = SharedNodes::<Buffer>::default();
2305 let mut shared_buffer_leases = SharedNodes::<crate::pool::Lease<Buffer>>::default();
2306 let mut shared_images = SharedNodes::<Image>::default();
2307 let mut shared_image_leases = SharedNodes::<crate::pool::Lease<Image>>::default();
2308 let mut shared_accels = SharedNodes::<AccelerationStructure>::default();
2309 let mut shared_accel_leases =
2310 SharedNodes::<crate::pool::Lease<AccelerationStructure>>::default();
2311 let accel_supported = device.physical.vk_khr_acceleration_structure.is_some();
2312
2313 let mut resource_kinds = vec![
2314 ResourceKind::OwnedBuffer,
2315 ResourceKind::SharedBuffer,
2316 ResourceKind::OwnedBufferLease,
2317 ResourceKind::SharedBufferLease,
2318 ResourceKind::OwnedImage,
2319 ResourceKind::SharedImage,
2320 ResourceKind::OwnedImageLease,
2321 ResourceKind::SharedImageLease,
2322 ResourceKind::SwapchainImage,
2323 ];
2324
2325 if accel_supported {
2326 resource_kinds.push(ResourceKind::OwnedAccelerationStructure);
2327 resource_kinds.push(ResourceKind::SharedAccelerationStructure);
2328 resource_kinds.push(ResourceKind::OwnedAccelerationStructureLease);
2329 resource_kinds.push(ResourceKind::SharedAccelerationStructureLease);
2330 }
2331
2332 for step in 0..64 {
2333 let kind = resource_kinds
2334 [(next_rand(&mut rand_state) as usize) % resource_kinds.len()];
2335 let expect_new = match kind {
2336 ResourceKind::OwnedBuffer
2337 | ResourceKind::OwnedBufferLease
2338 | ResourceKind::OwnedImage
2339 | ResourceKind::OwnedImageLease
2340 | ResourceKind::SwapchainImage
2341 | ResourceKind::OwnedAccelerationStructure
2342 | ResourceKind::OwnedAccelerationStructureLease => true,
2343 ResourceKind::SharedBuffer => {
2344 shared_buffers.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2345 }
2346 ResourceKind::SharedBufferLease => {
2347 shared_buffer_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2348 }
2349 ResourceKind::SharedImage => {
2350 shared_images.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2351 }
2352 ResourceKind::SharedImageLease => {
2353 shared_image_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2354 }
2355 ResourceKind::SharedAccelerationStructure => {
2356 shared_accels.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2357 }
2358 ResourceKind::SharedAccelerationStructureLease => {
2359 shared_accel_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2360 }
2361 };
2362
2363 let expected_node_idx = graph.resources.len();
2364
2365 let node_idx = match kind {
2366 ResourceKind::OwnedBuffer => graph
2367 .bind_resource(Buffer::create(
2368 &device,
2369 BufferInfo::device_mem(
2370 16 + step,
2371 vk::BufferUsageFlags::STORAGE_BUFFER,
2372 ),
2373 )?)
2374 .index(),
2375 ResourceKind::SharedBuffer if expect_new => {
2376 let resource = Arc::new(Buffer::create(
2377 &device,
2378 BufferInfo::device_mem(
2379 16 + step,
2380 vk::BufferUsageFlags::STORAGE_BUFFER,
2381 ),
2382 )?);
2383 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2384 shared_buffers.push(resource, node_idx);
2385 node_idx
2386 }
2387 ResourceKind::SharedBuffer => {
2388 let reuse_idx =
2389 (next_rand(&mut rand_state) as usize) % shared_buffers.len();
2390 let (resource, node_idx) = shared_buffers.get(reuse_idx).unwrap();
2391 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2392 node_idx
2393 }
2394 ResourceKind::OwnedBufferLease => graph
2395 .bind_resource(pool.resource(BufferInfo::device_mem(
2396 32 + step,
2397 vk::BufferUsageFlags::STORAGE_BUFFER,
2398 ))?)
2399 .index(),
2400 ResourceKind::SharedBufferLease if expect_new => {
2401 let resource = Arc::new(pool.resource(BufferInfo::device_mem(
2402 32 + step,
2403 vk::BufferUsageFlags::STORAGE_BUFFER,
2404 ))?);
2405 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2406 shared_buffer_leases.push(resource, node_idx);
2407 node_idx
2408 }
2409 ResourceKind::SharedBufferLease => {
2410 let reuse_idx =
2411 (next_rand(&mut rand_state) as usize) % shared_buffer_leases.len();
2412 let (resource, node_idx) = shared_buffer_leases.get(reuse_idx).unwrap();
2413 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2414 node_idx
2415 }
2416 ResourceKind::OwnedImage => graph
2417 .bind_resource(Image::create(
2418 &device,
2419 ImageInfo::image_2d(
2420 1,
2421 1,
2422 vk::Format::R8G8B8A8_UNORM,
2423 vk::ImageUsageFlags::SAMPLED,
2424 ),
2425 )?)
2426 .index(),
2427 ResourceKind::SharedImage if expect_new => {
2428 let resource = Arc::new(Image::create(
2429 &device,
2430 ImageInfo::image_2d(
2431 1,
2432 1,
2433 vk::Format::R8G8B8A8_UNORM,
2434 vk::ImageUsageFlags::SAMPLED,
2435 ),
2436 )?);
2437 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2438 shared_images.push(resource, node_idx);
2439 node_idx
2440 }
2441 ResourceKind::SharedImage => {
2442 let reuse_idx =
2443 (next_rand(&mut rand_state) as usize) % shared_images.len();
2444 let (resource, node_idx) = shared_images.get(reuse_idx).unwrap();
2445 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2446 node_idx
2447 }
2448 ResourceKind::OwnedImageLease => graph
2449 .bind_resource(pool.resource(ImageInfo::image_2d(
2450 1,
2451 1,
2452 vk::Format::R8G8B8A8_UNORM,
2453 vk::ImageUsageFlags::SAMPLED,
2454 ))?)
2455 .index(),
2456 ResourceKind::SharedImageLease if expect_new => {
2457 let resource = Arc::new(pool.resource(ImageInfo::image_2d(
2458 1,
2459 1,
2460 vk::Format::R8G8B8A8_UNORM,
2461 vk::ImageUsageFlags::SAMPLED,
2462 ))?);
2463 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2464 shared_image_leases.push(resource, node_idx);
2465 node_idx
2466 }
2467 ResourceKind::SharedImageLease => {
2468 let reuse_idx =
2469 (next_rand(&mut rand_state) as usize) % shared_image_leases.len();
2470 let (resource, node_idx) = shared_image_leases.get(reuse_idx).unwrap();
2471 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2472 node_idx
2473 }
2474 ResourceKind::SwapchainImage => graph
2475 .bind_resource(SwapchainImage::from_raw(
2476 &device,
2477 vk::Image::null(),
2478 ImageInfo::image_2d(
2479 1,
2480 1,
2481 vk::Format::R8G8B8A8_UNORM,
2482 vk::ImageUsageFlags::COLOR_ATTACHMENT,
2483 ),
2484 step as u32,
2485 ))
2486 .index(),
2487 ResourceKind::OwnedAccelerationStructure => graph
2488 .bind_resource(AccelerationStructure::create(
2489 &device,
2490 AccelerationStructureInfo::blas(256 + step),
2491 )?)
2492 .index(),
2493 ResourceKind::SharedAccelerationStructure if expect_new => {
2494 let resource = Arc::new(AccelerationStructure::create(
2495 &device,
2496 AccelerationStructureInfo::blas(256 + step),
2497 )?);
2498 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2499 shared_accels.push(resource, node_idx);
2500 node_idx
2501 }
2502 ResourceKind::SharedAccelerationStructure => {
2503 let reuse_idx =
2504 (next_rand(&mut rand_state) as usize) % shared_accels.len();
2505 let (resource, node_idx) = shared_accels.get(reuse_idx).unwrap();
2506 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2507 node_idx
2508 }
2509 ResourceKind::OwnedAccelerationStructureLease => graph
2510 .bind_resource(
2511 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2512 )
2513 .index(),
2514 ResourceKind::SharedAccelerationStructureLease if expect_new => {
2515 let resource = Arc::new(
2516 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2517 );
2518 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2519 shared_accel_leases.push(resource, node_idx);
2520 node_idx
2521 }
2522 ResourceKind::SharedAccelerationStructureLease => {
2523 let reuse_idx =
2524 (next_rand(&mut rand_state) as usize) % shared_accel_leases.len();
2525 let (resource, node_idx) = shared_accel_leases.get(reuse_idx).unwrap();
2526 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2527 node_idx
2528 }
2529 };
2530
2531 if expect_new {
2532 assert_eq!(node_idx, expected_node_idx);
2533 assert_eq!(graph.resources.len(), expected_node_idx + 1);
2534 } else {
2535 assert!(node_idx < expected_node_idx);
2536 assert_eq!(graph.resources.len(), expected_node_idx);
2537 }
2538 }
2539
2540 Ok(())
2541 }
2542 }
2543 }
2544}