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