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