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 cmp::Ord,
62 collections::{BTreeMap, HashMap},
63 fmt::{Debug, Formatter},
64 mem,
65 ops::Range,
66 ops::{Deref, DerefMut},
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
966 #[cfg(feature = "checked")]
967 graph_id: GraphId,
968}
969
970pub struct GraphBuilder {
972 graph: Graph,
973}
974
975impl GraphBuilder {
976 pub fn new() -> Self {
978 Self {
979 graph: Graph::new(),
980 }
981 }
982
983 pub fn build(self) -> Graph {
985 self.graph
986 }
987
988 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
990 where
991 R: Resource,
992 {
993 self.graph.bind_resource(resource)
994 }
995
996 pub fn blit_image(
998 mut self,
999 src: impl Into<AnyImageNode>,
1000 dst: impl Into<AnyImageNode>,
1001 filter: vk::Filter,
1002 ) -> Self {
1003 self.graph.blit_image(src, dst, filter);
1004 self
1005 }
1006
1007 pub fn clear_color_image(
1009 mut self,
1010 image: impl Into<AnyImageNode>,
1011 color: impl Into<ClearColorValue>,
1012 ) -> Self {
1013 self.graph.clear_color_image(image, color);
1014 self
1015 }
1016
1017 pub fn clear_depth_stencil_image(
1019 mut self,
1020 image: impl Into<AnyImageNode>,
1021 depth: f32,
1022 stencil: u32,
1023 ) -> Self {
1024 self.graph.clear_depth_stencil_image(image, depth, stencil);
1025 self
1026 }
1027
1028 pub fn copy_buffer(
1030 mut self,
1031 src: impl Into<AnyBufferNode>,
1032 dst: impl Into<AnyBufferNode>,
1033 ) -> Self {
1034 self.graph.copy_buffer(src, dst);
1035 self
1036 }
1037
1038 pub fn copy_buffer_to_image(
1040 mut self,
1041 src: impl Into<AnyBufferNode>,
1042 dst: impl Into<AnyImageNode>,
1043 ) -> Self {
1044 self.graph.copy_buffer_to_image(src, dst);
1045 self
1046 }
1047
1048 pub fn copy_image(
1050 mut self,
1051 src: impl Into<AnyImageNode>,
1052 dst: impl Into<AnyImageNode>,
1053 ) -> Self {
1054 self.graph.copy_image(src, dst);
1055 self
1056 }
1057
1058 pub fn copy_image_to_buffer(
1060 mut self,
1061 src: impl Into<AnyImageNode>,
1062 dst: impl Into<AnyBufferNode>,
1063 ) -> Self {
1064 self.graph.copy_image_to_buffer(src, dst);
1065 self
1066 }
1067
1068 pub fn fill_buffer(
1070 mut self,
1071 buffer: impl Into<AnyBufferNode>,
1072 region: Range<vk::DeviceSize>,
1073 data: u32,
1074 ) -> Self {
1075 self.graph.fill_buffer(buffer, region, data);
1076 self
1077 }
1078
1079 pub fn update_buffer(
1081 mut self,
1082 buffer: impl Into<AnyBufferNode>,
1083 offset: vk::DeviceSize,
1084 data: impl AsRef<[u8]> + 'static + Send,
1085 ) -> Self {
1086 self.graph.update_buffer(buffer, offset, data);
1087 self
1088 }
1089}
1090
1091impl Default for GraphBuilder {
1092 fn default() -> Self {
1093 Self::new()
1094 }
1095}
1096
1097impl Default for Graph {
1098 fn default() -> Self {
1099 Self {
1100 cmds: Default::default(),
1101 resources: Default::default(),
1102
1103 #[cfg(feature = "checked")]
1104 graph_id: GraphId::next(),
1105 }
1106 }
1107}
1108
1109impl Graph {
1110 pub fn new() -> Self {
1112 Self::default()
1113 }
1114
1115 pub fn builder() -> GraphBuilder {
1117 GraphBuilder::new()
1118 }
1119
1120 pub fn into_builder(self) -> GraphBuilder {
1122 GraphBuilder { graph: self }
1123 }
1124
1125 pub(crate) fn assert_node_owner<N>(&self, _resource_node: &N)
1126 where
1127 N: Node,
1128 {
1129 #[cfg(feature = "checked")]
1130 _resource_node.assert_owner(self.graph_id);
1131 }
1132
1133 #[cfg(feature = "checked")]
1134 pub(crate) fn graph_id(&self) -> GraphId {
1135 self.graph_id
1136 }
1137
1138 pub fn begin_cmd(&mut self) -> Command<'_> {
1140 Command::new(self)
1141 }
1142
1143 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
1148 where
1149 R: Resource,
1150 {
1151 resource.bind_graph(self)
1152 }
1153
1154 pub(crate) fn bind_stream_arg_resource(&mut self, resource: AnyResource) -> NodeIndex {
1155 self.resources.bind(resource)
1156 }
1157
1158 pub fn blit_image(
1165 &mut self,
1166 src: impl Into<AnyImageNode>,
1167 dst: impl Into<AnyImageNode>,
1168 filter: vk::Filter,
1169 ) -> &mut Self {
1170 let src = src.into();
1171 let src_info = self.resources[src.index()].expect_image_info();
1172
1173 let dst = dst.into();
1174 let dst_info = self.resources[dst.index()].expect_image_info();
1175
1176 self.begin_cmd()
1177 .debug_name("blit image")
1178 .blit_image(
1179 src,
1180 dst,
1181 filter,
1182 [vk::ImageBlit {
1183 src_subresource: vk::ImageSubresourceLayers {
1184 aspect_mask: format_aspect_mask(src_info.format),
1185 mip_level: 0,
1186 base_array_layer: 0,
1187 layer_count: 1,
1188 },
1189 src_offsets: [
1190 vk::Offset3D { x: 0, y: 0, z: 0 },
1191 vk::Offset3D {
1192 x: src_info.width as _,
1193 y: src_info.height as _,
1194 z: src_info.depth as _,
1195 },
1196 ],
1197 dst_subresource: vk::ImageSubresourceLayers {
1198 aspect_mask: format_aspect_mask(dst_info.format),
1199 mip_level: 0,
1200 base_array_layer: 0,
1201 layer_count: 1,
1202 },
1203 dst_offsets: [
1204 vk::Offset3D { x: 0, y: 0, z: 0 },
1205 vk::Offset3D {
1206 x: dst_info.width as _,
1207 y: dst_info.height as _,
1208 z: dst_info.depth as _,
1209 },
1210 ],
1211 }],
1212 )
1213 .end_cmd()
1214 }
1215
1216 #[profiling::function]
1223 #[doc(hidden)]
1224 #[deprecated(note = "use Graph::begin_cmd().blit_image(...).end_cmd() for explicit regions")]
1225 pub fn blit_image_region(
1226 &mut self,
1227 src: impl Into<AnyImageNode>,
1228 dst: impl Into<AnyImageNode>,
1229 filter: vk::Filter,
1230 regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
1231 ) -> &mut Self {
1232 self.begin_cmd()
1233 .debug_name("blit image")
1234 .blit_image(src, dst, filter, regions)
1235 .end_cmd()
1236 }
1237
1238 #[profiling::function]
1245 pub fn clear_color_image(
1246 &mut self,
1247 image: impl Into<AnyImageNode>,
1248 color: impl Into<ClearColorValue>,
1249 ) -> &mut Self {
1250 self.begin_cmd()
1251 .debug_name("clear color")
1252 .clear_color_image(image, color)
1253 .end_cmd()
1254 }
1255
1256 #[profiling::function]
1263 pub fn clear_depth_stencil_image(
1264 &mut self,
1265 image: impl Into<AnyImageNode>,
1266 depth: f32,
1267 stencil: u32,
1268 ) -> &mut Self {
1269 self.begin_cmd()
1270 .debug_name("clear depth/stencil")
1271 .clear_depth_stencil_image(image, depth, stencil)
1272 .end_cmd()
1273 }
1274
1275 pub fn copy_buffer(
1282 &mut self,
1283 src: impl Into<AnyBufferNode>,
1284 dst: impl Into<AnyBufferNode>,
1285 ) -> &mut Self {
1286 let src = src.into();
1287 let dst = dst.into();
1288 let src_info = self.resources[src.index()].expect_buffer_info();
1289 let dst_info = self.resources[dst.index()].expect_buffer_info();
1290
1291 self.begin_cmd()
1292 .debug_name("copy buffer")
1293 .copy_buffer(
1294 src,
1295 dst,
1296 [vk::BufferCopy {
1297 src_offset: 0,
1298 dst_offset: 0,
1299 size: src_info.size.min(dst_info.size),
1300 }],
1301 )
1302 .end_cmd()
1303 }
1304
1305 #[profiling::function]
1312 #[doc(hidden)]
1313 #[deprecated(note = "use Graph::begin_cmd().copy_buffer(...).end_cmd() for explicit regions")]
1314 pub fn copy_buffer_region(
1315 &mut self,
1316 src: impl Into<AnyBufferNode>,
1317 dst: impl Into<AnyBufferNode>,
1318 regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
1319 ) -> &mut Self {
1320 self.begin_cmd()
1321 .debug_name("copy buffer")
1322 .copy_buffer(src, dst, regions)
1323 .end_cmd()
1324 }
1325
1326 pub fn copy_buffer_to_image(
1332 &mut self,
1333 src: impl Into<AnyBufferNode>,
1334 dst: impl Into<AnyImageNode>,
1335 ) -> &mut Self {
1336 let dst = dst.into();
1337 let dst_info = self.resources[dst.index()].expect_image_info();
1338
1339 self.begin_cmd()
1340 .debug_name("copy buffer to image")
1341 .copy_buffer_to_image(
1342 src,
1343 dst,
1344 [vk::BufferImageCopy {
1345 buffer_offset: 0,
1346 buffer_row_length: dst_info.width,
1347 buffer_image_height: dst_info.height,
1348 image_subresource: vk::ImageSubresourceLayers {
1349 aspect_mask: format_aspect_mask(dst_info.format),
1350 mip_level: 0,
1351 base_array_layer: 0,
1352 layer_count: 1,
1353 },
1354 image_offset: Default::default(),
1355 image_extent: vk::Extent3D {
1356 depth: dst_info.depth,
1357 height: dst_info.height,
1358 width: dst_info.width,
1359 },
1360 }],
1361 )
1362 .end_cmd()
1363 }
1364
1365 #[profiling::function]
1372 #[doc(hidden)]
1373 #[deprecated(
1374 note = "use Graph::begin_cmd().copy_buffer_to_image(...).end_cmd() for explicit regions"
1375 )]
1376 pub fn copy_buffer_to_image_region(
1377 &mut self,
1378 src: impl Into<AnyBufferNode>,
1379 dst: impl Into<AnyImageNode>,
1380 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1381 ) -> &mut Self {
1382 self.begin_cmd()
1383 .debug_name("copy buffer to image")
1384 .copy_buffer_to_image(src, dst, regions)
1385 .end_cmd()
1386 }
1387
1388 pub fn copy_image(
1395 &mut self,
1396 src: impl Into<AnyImageNode>,
1397 dst: impl Into<AnyImageNode>,
1398 ) -> &mut Self {
1399 let src = src.into();
1400 let src_info = self.resources[src.index()].expect_image_info();
1401
1402 let dst = dst.into();
1403 let dst_info = self.resources[dst.index()].expect_image_info();
1404
1405 self.begin_cmd()
1406 .debug_name("copy image")
1407 .copy_image(
1408 src,
1409 dst,
1410 [vk::ImageCopy {
1411 src_subresource: vk::ImageSubresourceLayers {
1412 aspect_mask: format_aspect_mask(src_info.format),
1413 mip_level: 0,
1414 base_array_layer: 0,
1415 layer_count: src_info.array_layer_count,
1416 },
1417 src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1418 dst_subresource: vk::ImageSubresourceLayers {
1419 aspect_mask: format_aspect_mask(dst_info.format),
1420 mip_level: 0,
1421 base_array_layer: 0,
1422 layer_count: src_info.array_layer_count,
1423 },
1424 dst_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1425 extent: vk::Extent3D {
1426 depth: src_info.depth.clamp(1, dst_info.depth),
1427 height: src_info.height.clamp(1, dst_info.height),
1428 width: src_info.width.min(dst_info.width),
1429 },
1430 }],
1431 )
1432 .end_cmd()
1433 }
1434
1435 #[profiling::function]
1442 #[doc(hidden)]
1443 #[deprecated(note = "use Graph::begin_cmd().copy_image(...).end_cmd() for explicit regions")]
1444 pub fn copy_image_region(
1445 &mut self,
1446 src: impl Into<AnyImageNode>,
1447 dst: impl Into<AnyImageNode>,
1448 regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
1449 ) -> &mut Self {
1450 self.begin_cmd()
1451 .debug_name("copy image")
1452 .copy_image(src, dst, regions)
1453 .end_cmd()
1454 }
1455
1456 pub fn copy_image_to_buffer(
1462 &mut self,
1463 src: impl Into<AnyImageNode>,
1464 dst: impl Into<AnyBufferNode>,
1465 ) -> &mut Self {
1466 let src = src.into();
1467 let dst = dst.into();
1468
1469 let src_info = self.resources[src.index()].expect_image_info();
1470
1471 self.begin_cmd()
1472 .debug_name("copy image to buffer")
1473 .copy_image_to_buffer(
1474 src,
1475 dst,
1476 [vk::BufferImageCopy {
1477 buffer_offset: 0,
1478 buffer_row_length: src_info.width,
1479 buffer_image_height: src_info.height,
1480 image_subresource: vk::ImageSubresourceLayers {
1481 aspect_mask: format_aspect_mask(src_info.format),
1482 mip_level: 0,
1483 base_array_layer: 0,
1484 layer_count: 1,
1485 },
1486 image_offset: Default::default(),
1487 image_extent: vk::Extent3D {
1488 depth: src_info.depth,
1489 height: src_info.height,
1490 width: src_info.width,
1491 },
1492 }],
1493 )
1494 .end_cmd()
1495 }
1496
1497 #[profiling::function]
1504 #[doc(hidden)]
1505 #[deprecated(
1506 note = "use Graph::begin_cmd().copy_image_to_buffer(...).end_cmd() for explicit regions"
1507 )]
1508 pub fn copy_image_to_buffer_region(
1509 &mut self,
1510 src: impl Into<AnyImageNode>,
1511 dst: impl Into<AnyBufferNode>,
1512 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1513 ) -> &mut Self {
1514 self.begin_cmd()
1515 .debug_name("copy image to buffer")
1516 .copy_image_to_buffer(src, dst, regions)
1517 .end_cmd()
1518 }
1519
1520 pub fn fill_buffer(
1526 &mut self,
1527 buffer: impl Into<AnyBufferNode>,
1528 region: Range<vk::DeviceSize>,
1529 data: u32,
1530 ) -> &mut Self {
1531 self.begin_cmd()
1532 .debug_name("fill buffer")
1533 .fill_buffer(buffer, region, data)
1534 .end_cmd()
1535 }
1536
1537 #[profiling::function]
1539 fn first_node_access_pass_index(&self, resource_node: impl Node) -> Option<usize> {
1540 self.assert_node_owner(&resource_node);
1541
1542 let node_idx = resource_node.index();
1543
1544 for (pass_idx, pass) in self.cmds.iter().enumerate() {
1545 for exec in pass.execs.iter() {
1546 if exec.accesses.contains(node_idx) {
1547 return Some(pass_idx);
1548 }
1549 }
1550 }
1551
1552 None
1553 }
1554
1555 #[profiling::function]
1558 pub fn finalize(mut self) -> Submission {
1559 self.cmds.retain_mut(|cmd| {
1561 debug_assert!(cmd.expect_last_exec().func.is_none());
1562
1563 cmd.execs.pop();
1564
1565 for exec in &mut cmd.execs {
1566 exec.accesses.freeze();
1567 }
1568
1569 !cmd.execs.is_empty()
1570 });
1571
1572 Submission::new(self)
1573 }
1574
1575 pub fn resource<N>(&self, resource_node: N) -> &N::Resource
1592 where
1593 N: Node,
1594 {
1595 self.assert_node_owner(&resource_node);
1596 resource_node.borrow(&self.resources)
1597 }
1598
1599 #[profiling::function]
1608 pub fn update_buffer(
1609 &mut self,
1610 buffer: impl Into<AnyBufferNode>,
1611 offset: vk::DeviceSize,
1612 data: impl AsRef<[u8]> + 'static + Send,
1613 ) -> &mut Self {
1614 debug_assert!(data.as_ref().len() <= 64 * 1024);
1615
1616 let buffer = buffer.into();
1617 let data_end = offset + data.as_ref().len() as vk::DeviceSize;
1618
1619 #[cfg(feature = "checked")]
1620 {
1621 assert!(
1622 data.as_ref().len() <= 64 * 1024,
1623 "data length ({}) exceeds vkCmdUpdateBuffer limit (65536)",
1624 data.as_ref().len()
1625 );
1626
1627 let buffer_info = self.resources[buffer.index()].expect_buffer_info();
1628
1629 assert!(
1630 data_end <= buffer_info.size,
1631 "data range end ({data_end}) exceeds buffer size ({})",
1632 buffer_info.size
1633 );
1634 }
1635
1636 let data = Arc::<[u8]>::from(data.as_ref());
1637
1638 self.begin_cmd()
1639 .debug_name("update buffer")
1640 .subresource_access(buffer, offset..data_end, AccessType::TransferWrite)
1641 .record_stream(move |cmd| {
1642 let buffer = cmd.resource(buffer);
1643
1644 unsafe {
1645 cmd.device
1646 .cmd_update_buffer(cmd.handle, buffer.handle, offset, &data);
1647 }
1648 })
1649 .end_cmd()
1650 }
1651}
1652
1653#[derive(Clone, Copy, Debug)]
1658pub enum LoadOp<T> {
1659 Clear(T),
1664
1665 DontCare,
1667
1668 Load,
1670}
1671
1672#[allow(private_bounds)]
1678pub trait Node: private::NodeSealed {
1679 type Resource;
1681
1682 type SyncInfo;
1684
1685 #[doc(hidden)]
1686 fn index(&self) -> usize;
1687}
1688
1689#[derive(Clone, Debug)]
1690struct NodeAccess {
1691 node_idx: NodeIndex,
1692 accesses: Box<[SubresourceAccess]>,
1693}
1694
1695#[derive(Clone, Debug)]
1696struct NodeAccessBuilder {
1697 node_idx: NodeIndex,
1698 accesses: SmallVec<[SubresourceAccess; 2]>,
1699}
1700
1701mod private {
1702 use super::{AnyResource, Node};
1703
1704 #[cfg(feature = "checked")]
1705 use super::GraphId;
1706
1707 pub(crate) trait NodeSealed: Sized {
1709 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource
1710 where
1711 Self: Node;
1712
1713 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource
1714 where
1715 Self: Node,
1716 {
1717 debug_assert_eq!(self.index(), index);
1718 self.borrow(resources)
1719 }
1720
1721 #[cfg(feature = "checked")]
1722 fn assert_owner(&self, _graph_id: GraphId) {}
1723 }
1724
1725 pub(crate) trait ResourceSealed {}
1727}
1728
1729#[allow(private_bounds)]
1736pub trait Resource: private::ResourceSealed {
1737 type Node;
1739
1740 #[doc(hidden)]
1741 fn bind_graph(self, _: &mut Graph) -> Self::Node;
1742}
1743
1744impl private::ResourceSealed for SwapchainImage {}
1745
1746impl Resource for SwapchainImage {
1747 type Node = SwapchainImageNode;
1748
1749 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1750 let node = Self::Node::new(
1751 graph.resources.len(),
1752 #[cfg(feature = "checked")]
1753 graph.graph_id,
1754 );
1755
1756 let resource = AnyResource::SwapchainImage(Box::new(self));
1759 graph.resources.bind(resource);
1760
1761 node
1762 }
1763}
1764
1765macro_rules! resource {
1766 ($name:ident) => {
1767 paste::paste! {
1768 impl private::ResourceSealed for $name {}
1769 impl private::ResourceSealed for Arc<$name> {}
1770 impl<'a> private::ResourceSealed for &'a Arc<$name> {}
1771 impl private::ResourceSealed for Lease<$name> {}
1772 impl private::ResourceSealed for Arc<Lease<$name>> {}
1773 impl<'a> private::ResourceSealed for &'a Arc<Lease<$name>> {}
1774
1775 impl Resource for $name {
1776 type Node = [<$name Node>];
1777
1778 #[profiling::function]
1779 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1780 Arc::new(self).bind_graph(graph)
1784 }
1785 }
1786
1787 impl Resource for Arc<$name> {
1788 type Node = [<$name Node>];
1789
1790 #[profiling::function]
1791 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1792 Self::Node::new(
1796 graph.resources.bind_shared(self),
1797 #[cfg(feature = "checked")]
1798 graph.graph_id,
1799 )
1800 }
1801 }
1802
1803 impl<'a> Resource for &'a Arc<$name> {
1804 type Node = [<$name Node>];
1805
1806 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1807 Arc::clone(self).bind_graph(graph)
1810 }
1811 }
1812
1813 impl Resource for Lease<$name> {
1814 type Node = [<$name LeaseNode>];
1815
1816 #[profiling::function]
1817 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1818 Arc::new(self).bind_graph(graph)
1822 }
1823 }
1824
1825 impl Resource for Arc<Lease<$name>> {
1826 type Node = [<$name LeaseNode>];
1827
1828 #[profiling::function]
1829 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1830 Self::Node::new(
1835 graph.resources.bind_shared(self),
1836 #[cfg(feature = "checked")]
1837 graph.graph_id,
1838 )
1839 }
1840 }
1841
1842 impl<'a> Resource for &'a Arc<Lease<$name>> {
1843 type Node = [<$name LeaseNode>];
1844
1845 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1846 Arc::clone(self).bind_graph(graph)
1850 }
1851 }
1852 }
1853 };
1854}
1855
1856resource!(AccelerationStructure);
1857resource!(Image);
1858resource!(Buffer);
1859
1860#[derive(Debug, Default)]
1861struct ResourceMap {
1862 addr_index: HashMap<usize, NodeIndex>,
1863 resources: Vec<AnyResource>,
1864}
1865
1866impl ResourceMap {
1867 pub(crate) fn from_resources(resources: Vec<AnyResource>) -> Self {
1868 Self {
1869 addr_index: HashMap::new(),
1870 resources,
1871 }
1872 }
1873
1874 fn bind(&mut self, resource: AnyResource) -> NodeIndex {
1875 let node_idx = self.resources.len();
1876 self.resources.push(resource);
1877
1878 node_idx
1879 }
1880
1881 fn bind_shared<T>(&mut self, resource: Arc<T>) -> NodeIndex
1882 where
1883 Arc<T>: Into<AnyResource>,
1884 {
1885 let addr = Arc::as_ptr(&resource) as usize;
1886
1887 *self.addr_index.entry(addr).or_insert_with(|| {
1888 let node_idx = self.resources.len();
1889 self.resources.push(resource.into());
1890
1891 node_idx
1892 })
1893 }
1894}
1895
1896impl Deref for ResourceMap {
1897 type Target = [AnyResource];
1898
1899 fn deref(&self) -> &Self::Target {
1900 &self.resources
1901 }
1902}
1903
1904impl DerefMut for ResourceMap {
1905 fn deref_mut(&mut self) -> &mut Self::Target {
1906 &mut self.resources
1907 }
1908}
1909
1910#[derive(Clone, Copy, Debug, PartialEq)]
1915pub enum StoreOp {
1916 DontCare,
1918
1919 Store,
1921}
1922
1923#[cfg(test)]
1924mod test {
1925 use std::sync::Arc;
1926
1927 use ash::vk;
1928
1929 use super::{
1930 AnyResource, CommandExecutionAbandoned, CommandExecutions, Graph, Node, ResourceMap,
1931 };
1932 use crate::driver::{
1933 DriverError,
1934 accel_struct::{AccelerationStructure, AccelerationStructureInfo},
1935 buffer::{Buffer, BufferInfo},
1936 device::{Device, DeviceInfo},
1937 image::{Image, ImageInfo},
1938 swapchain::SwapchainImage,
1939 };
1940 use crate::pool::{Pool, hash::HashPool};
1941
1942 #[test]
1943 fn command_execution_starts_pending() {
1944 let mut graph = Graph::new();
1945 let mut cmd = graph.begin_cmd();
1946 let execution = cmd.track_execution();
1947
1948 assert_eq!(execution.has_executed(), Ok(false));
1949 }
1950
1951 #[test]
1952 fn command_execution_is_abandoned_when_graph_drops() {
1953 let execution = {
1954 let mut graph = Graph::new();
1955 let mut cmd = graph.begin_cmd();
1956
1957 cmd.track_execution()
1958 };
1959
1960 assert_eq!(execution.has_executed(), Err(CommandExecutionAbandoned));
1961 }
1962
1963 #[test]
1964 fn command_executions_track_multiple_handles() {
1965 let mut executions = CommandExecutions::default();
1966 let first = executions.track();
1967 let second = executions.track();
1968
1969 executions.signal_executed();
1970
1971 assert_eq!(first.has_executed(), Ok(true));
1972 assert_eq!(second.has_executed(), Ok(true));
1973 }
1974
1975 #[test]
1976 fn command_executions_extend_preserves_both_sides() {
1977 let mut lhs = CommandExecutions::default();
1978 let first = lhs.track();
1979 let mut rhs = CommandExecutions::default();
1980 let second = rhs.track();
1981
1982 lhs.extend(rhs);
1983 lhs.signal_executed();
1984
1985 assert_eq!(first.has_executed(), Ok(true));
1986 assert_eq!(second.has_executed(), Ok(true));
1987 }
1988
1989 #[test]
1990 fn command_execution_stays_executed_after_tracker_drops() {
1991 let execution = {
1992 let mut executions = CommandExecutions::default();
1993 let execution = executions.track();
1994
1995 executions.signal_executed();
1996
1997 execution
1998 };
1999
2000 assert_eq!(execution.has_executed(), Ok(true));
2001 }
2002
2003 #[test]
2004 fn command_execution_abandoned_converts_to_driver_error() {
2005 let error = DriverError::from(CommandExecutionAbandoned);
2006
2007 assert!(matches!(error, DriverError::InvalidData));
2008 }
2009
2010 mod integration {
2011 use super::*;
2012
2013 fn test_device() -> Result<Device, DriverError> {
2014 Device::create(DeviceInfo::default())
2015 }
2016
2017 mod resource_map {
2018 use super::*;
2019
2020 #[test]
2021 #[ignore = "requires Vulkan device"]
2022 fn bind_assigns_a_new_node_index_every_time() -> Result<(), DriverError> {
2023 let device = test_device()?;
2024 let buffer = Arc::new(Buffer::create(
2025 &device,
2026 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2027 )?);
2028 let image = Arc::new(Image::create(
2029 &device,
2030 ImageInfo::image_2d(
2031 1,
2032 1,
2033 vk::Format::R8G8B8A8_UNORM,
2034 vk::ImageUsageFlags::SAMPLED,
2035 ),
2036 )?);
2037 let mut resources = ResourceMap::default();
2038
2039 assert_eq!(resources.bind(AnyResource::from(buffer)), 0);
2040 assert_eq!(resources.bind(AnyResource::from(image)), 1);
2041 assert_eq!(resources.len(), 2);
2042
2043 Ok(())
2044 }
2045
2046 #[test]
2047 #[ignore = "requires Vulkan device"]
2048 fn bind_shared_reuses_the_existing_node_index_for_the_same_address()
2049 -> Result<(), DriverError> {
2050 let device = test_device()?;
2051 let buffer = Arc::new(Buffer::create(
2052 &device,
2053 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2054 )?);
2055 let mut resources = ResourceMap::default();
2056
2057 assert_eq!(resources.bind_shared(Arc::clone(&buffer)), 0);
2058 assert_eq!(resources.bind_shared(buffer), 0);
2059 assert_eq!(resources.len(), 1);
2060
2061 Ok(())
2062 }
2063
2064 #[test]
2065 #[ignore = "requires Vulkan device"]
2066 fn bind_shared_creates_distinct_node_indices_for_different_addresses()
2067 -> Result<(), DriverError> {
2068 let device = test_device()?;
2069 let buffer = Arc::new(Buffer::create(
2070 &device,
2071 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
2072 )?);
2073 let image = Arc::new(Image::create(
2074 &device,
2075 ImageInfo::image_2d(
2076 1,
2077 1,
2078 vk::Format::R8G8B8A8_UNORM,
2079 vk::ImageUsageFlags::SAMPLED,
2080 ),
2081 )?);
2082 let mut resources = ResourceMap::default();
2083
2084 assert_eq!(resources.bind_shared(buffer), 0);
2085 assert_eq!(resources.bind_shared(image), 1);
2086 assert_eq!(resources.len(), 2);
2087
2088 Ok(())
2089 }
2090
2091 #[test]
2092 #[ignore = "requires Vulkan device"]
2093 fn graph_bind_fuzzes_all_resource_paths() -> Result<(), DriverError> {
2094 #[derive(Clone, Copy)]
2095 enum ResourceKind {
2096 OwnedBuffer,
2097 SharedBuffer,
2098 OwnedBufferLease,
2099 SharedBufferLease,
2100 OwnedImage,
2101 SharedImage,
2102 OwnedImageLease,
2103 SharedImageLease,
2104 SwapchainImage,
2105 OwnedAccelerationStructure,
2106 SharedAccelerationStructure,
2107 OwnedAccelerationStructureLease,
2108 SharedAccelerationStructureLease,
2109 }
2110
2111 struct SharedNodes<T> {
2112 values: Vec<(Arc<T>, usize)>,
2113 }
2114
2115 impl<T> Default for SharedNodes<T> {
2116 fn default() -> Self {
2117 Self { values: Vec::new() }
2118 }
2119 }
2120
2121 impl<T> SharedNodes<T> {
2122 fn get(&self, idx: usize) -> Option<(Arc<T>, usize)> {
2123 self.values
2124 .get(idx)
2125 .map(|(resource, node_idx)| (Arc::clone(resource), *node_idx))
2126 }
2127
2128 fn push(&mut self, resource: Arc<T>, node_idx: usize) {
2129 self.values.push((resource, node_idx));
2130 }
2131
2132 fn len(&self) -> usize {
2133 self.values.len()
2134 }
2135 }
2136
2137 fn next_rand(state: &mut u64) -> u64 {
2138 *state ^= *state << 13;
2139 *state ^= *state >> 7;
2140 *state ^= *state << 17;
2141 *state
2142 }
2143
2144 let device = test_device()?;
2145 let mut pool = HashPool::new(&device);
2146 let mut graph = Graph::new();
2147
2148 let mut rand_state = 0x5eed_u64;
2149 let mut shared_buffers = SharedNodes::<Buffer>::default();
2150 let mut shared_buffer_leases = SharedNodes::<crate::pool::Lease<Buffer>>::default();
2151 let mut shared_images = SharedNodes::<Image>::default();
2152 let mut shared_image_leases = SharedNodes::<crate::pool::Lease<Image>>::default();
2153 let mut shared_accels = SharedNodes::<AccelerationStructure>::default();
2154 let mut shared_accel_leases =
2155 SharedNodes::<crate::pool::Lease<AccelerationStructure>>::default();
2156 let accel_supported = device.physical.vk_khr_acceleration_structure.is_some();
2157
2158 let mut resource_kinds = vec![
2159 ResourceKind::OwnedBuffer,
2160 ResourceKind::SharedBuffer,
2161 ResourceKind::OwnedBufferLease,
2162 ResourceKind::SharedBufferLease,
2163 ResourceKind::OwnedImage,
2164 ResourceKind::SharedImage,
2165 ResourceKind::OwnedImageLease,
2166 ResourceKind::SharedImageLease,
2167 ResourceKind::SwapchainImage,
2168 ];
2169
2170 if accel_supported {
2171 resource_kinds.push(ResourceKind::OwnedAccelerationStructure);
2172 resource_kinds.push(ResourceKind::SharedAccelerationStructure);
2173 resource_kinds.push(ResourceKind::OwnedAccelerationStructureLease);
2174 resource_kinds.push(ResourceKind::SharedAccelerationStructureLease);
2175 }
2176
2177 for step in 0..64 {
2178 let kind = resource_kinds
2179 [(next_rand(&mut rand_state) as usize) % resource_kinds.len()];
2180 let expect_new = match kind {
2181 ResourceKind::OwnedBuffer
2182 | ResourceKind::OwnedBufferLease
2183 | ResourceKind::OwnedImage
2184 | ResourceKind::OwnedImageLease
2185 | ResourceKind::SwapchainImage
2186 | ResourceKind::OwnedAccelerationStructure
2187 | ResourceKind::OwnedAccelerationStructureLease => true,
2188 ResourceKind::SharedBuffer => {
2189 shared_buffers.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2190 }
2191 ResourceKind::SharedBufferLease => {
2192 shared_buffer_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2193 }
2194 ResourceKind::SharedImage => {
2195 shared_images.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2196 }
2197 ResourceKind::SharedImageLease => {
2198 shared_image_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2199 }
2200 ResourceKind::SharedAccelerationStructure => {
2201 shared_accels.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2202 }
2203 ResourceKind::SharedAccelerationStructureLease => {
2204 shared_accel_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2205 }
2206 };
2207
2208 let expected_node_idx = graph.resources.len();
2209
2210 let node_idx = match kind {
2211 ResourceKind::OwnedBuffer => graph
2212 .bind_resource(Buffer::create(
2213 &device,
2214 BufferInfo::device_mem(
2215 16 + step,
2216 vk::BufferUsageFlags::STORAGE_BUFFER,
2217 ),
2218 )?)
2219 .index(),
2220 ResourceKind::SharedBuffer if expect_new => {
2221 let resource = Arc::new(Buffer::create(
2222 &device,
2223 BufferInfo::device_mem(
2224 16 + step,
2225 vk::BufferUsageFlags::STORAGE_BUFFER,
2226 ),
2227 )?);
2228 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2229 shared_buffers.push(resource, node_idx);
2230 node_idx
2231 }
2232 ResourceKind::SharedBuffer => {
2233 let reuse_idx =
2234 (next_rand(&mut rand_state) as usize) % shared_buffers.len();
2235 let (resource, node_idx) = shared_buffers.get(reuse_idx).unwrap();
2236 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2237 node_idx
2238 }
2239 ResourceKind::OwnedBufferLease => graph
2240 .bind_resource(pool.resource(BufferInfo::device_mem(
2241 32 + step,
2242 vk::BufferUsageFlags::STORAGE_BUFFER,
2243 ))?)
2244 .index(),
2245 ResourceKind::SharedBufferLease if expect_new => {
2246 let resource = Arc::new(pool.resource(BufferInfo::device_mem(
2247 32 + step,
2248 vk::BufferUsageFlags::STORAGE_BUFFER,
2249 ))?);
2250 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2251 shared_buffer_leases.push(resource, node_idx);
2252 node_idx
2253 }
2254 ResourceKind::SharedBufferLease => {
2255 let reuse_idx =
2256 (next_rand(&mut rand_state) as usize) % shared_buffer_leases.len();
2257 let (resource, node_idx) = shared_buffer_leases.get(reuse_idx).unwrap();
2258 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2259 node_idx
2260 }
2261 ResourceKind::OwnedImage => graph
2262 .bind_resource(Image::create(
2263 &device,
2264 ImageInfo::image_2d(
2265 1,
2266 1,
2267 vk::Format::R8G8B8A8_UNORM,
2268 vk::ImageUsageFlags::SAMPLED,
2269 ),
2270 )?)
2271 .index(),
2272 ResourceKind::SharedImage if expect_new => {
2273 let resource = Arc::new(Image::create(
2274 &device,
2275 ImageInfo::image_2d(
2276 1,
2277 1,
2278 vk::Format::R8G8B8A8_UNORM,
2279 vk::ImageUsageFlags::SAMPLED,
2280 ),
2281 )?);
2282 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2283 shared_images.push(resource, node_idx);
2284 node_idx
2285 }
2286 ResourceKind::SharedImage => {
2287 let reuse_idx =
2288 (next_rand(&mut rand_state) as usize) % shared_images.len();
2289 let (resource, node_idx) = shared_images.get(reuse_idx).unwrap();
2290 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2291 node_idx
2292 }
2293 ResourceKind::OwnedImageLease => graph
2294 .bind_resource(pool.resource(ImageInfo::image_2d(
2295 1,
2296 1,
2297 vk::Format::R8G8B8A8_UNORM,
2298 vk::ImageUsageFlags::SAMPLED,
2299 ))?)
2300 .index(),
2301 ResourceKind::SharedImageLease if expect_new => {
2302 let resource = Arc::new(pool.resource(ImageInfo::image_2d(
2303 1,
2304 1,
2305 vk::Format::R8G8B8A8_UNORM,
2306 vk::ImageUsageFlags::SAMPLED,
2307 ))?);
2308 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2309 shared_image_leases.push(resource, node_idx);
2310 node_idx
2311 }
2312 ResourceKind::SharedImageLease => {
2313 let reuse_idx =
2314 (next_rand(&mut rand_state) as usize) % shared_image_leases.len();
2315 let (resource, node_idx) = shared_image_leases.get(reuse_idx).unwrap();
2316 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2317 node_idx
2318 }
2319 ResourceKind::SwapchainImage => graph
2320 .bind_resource(SwapchainImage::from_raw(
2321 &device,
2322 vk::Image::null(),
2323 ImageInfo::image_2d(
2324 1,
2325 1,
2326 vk::Format::R8G8B8A8_UNORM,
2327 vk::ImageUsageFlags::COLOR_ATTACHMENT,
2328 ),
2329 step as u32,
2330 ))
2331 .index(),
2332 ResourceKind::OwnedAccelerationStructure => graph
2333 .bind_resource(AccelerationStructure::create(
2334 &device,
2335 AccelerationStructureInfo::blas(256 + step),
2336 )?)
2337 .index(),
2338 ResourceKind::SharedAccelerationStructure if expect_new => {
2339 let resource = Arc::new(AccelerationStructure::create(
2340 &device,
2341 AccelerationStructureInfo::blas(256 + step),
2342 )?);
2343 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2344 shared_accels.push(resource, node_idx);
2345 node_idx
2346 }
2347 ResourceKind::SharedAccelerationStructure => {
2348 let reuse_idx =
2349 (next_rand(&mut rand_state) as usize) % shared_accels.len();
2350 let (resource, node_idx) = shared_accels.get(reuse_idx).unwrap();
2351 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2352 node_idx
2353 }
2354 ResourceKind::OwnedAccelerationStructureLease => graph
2355 .bind_resource(
2356 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2357 )
2358 .index(),
2359 ResourceKind::SharedAccelerationStructureLease if expect_new => {
2360 let resource = Arc::new(
2361 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2362 );
2363 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2364 shared_accel_leases.push(resource, node_idx);
2365 node_idx
2366 }
2367 ResourceKind::SharedAccelerationStructureLease => {
2368 let reuse_idx =
2369 (next_rand(&mut rand_state) as usize) % shared_accel_leases.len();
2370 let (resource, node_idx) = shared_accel_leases.get(reuse_idx).unwrap();
2371 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2372 node_idx
2373 }
2374 };
2375
2376 if expect_new {
2377 assert_eq!(node_idx, expected_node_idx);
2378 assert_eq!(graph.resources.len(), expected_node_idx + 1);
2379 } else {
2380 assert!(node_idx < expected_node_idx);
2381 assert_eq!(graph.resources.len(), expected_node_idx);
2382 }
2383 }
2384
2385 Ok(())
2386 }
2387 }
2388 }
2389}