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, format_texel_block_extent, format_texel_block_size,
45 graphics::{DepthStencilInfo, GraphicsPipeline},
46 image::{ImageInfo, ImageViewInfo, SampleCount},
47 image_subresource_range_from_layers,
48 ray_tracing::RayTracingPipeline,
49 render_pass::ResolveMode,
50 shader::PipelineDescriptorInfo,
51 },
52 driver::{
53 accel_struct::AccelerationStructure, buffer::Buffer, image::Image,
54 swapchain::SwapchainImage,
55 },
56 pool::Lease,
57 submission::Submission,
58 },
59 ash::vk,
60 smallvec::SmallVec,
61 std::{
62 cmp::Ord,
63 collections::{BTreeMap, HashMap},
64 fmt::{Debug, Formatter},
65 mem,
66 ops::Range,
67 ops::{Deref, DerefMut},
68 slice::Iter,
69 sync::Arc,
70 },
71 vk_sync::AccessType,
72};
73
74#[cfg(feature = "checked")]
75use std::sync::atomic::{AtomicU64, Ordering};
76
77type CommandFn = Arc<dyn for<'a> Fn(CommandRef<'a>) + Send + Sync>;
78type CommandFnOnce = Box<dyn FnOnce(CommandRef) + Send>;
79type NodeIndex = usize;
80
81#[cfg(feature = "checked")]
82#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
83pub(crate) struct GraphId(u64);
84
85#[cfg(feature = "checked")]
86impl GraphId {
87 fn next() -> Self {
88 static NEXT_ID: AtomicU64 = AtomicU64::new(1);
89
90 Self(NEXT_ID.fetch_add(1, Ordering::Relaxed))
91 }
92}
93
94#[derive(Debug)]
95enum AnyResource {
96 AccelerationStructure(Arc<AccelerationStructure>),
97 AccelerationStructureArg(AccelerationStructureInfo),
98 AccelerationStructureLease(Arc<Lease<AccelerationStructure>>),
99 Buffer(Arc<Buffer>),
100 BufferArg(BufferInfo),
101 BufferLease(Arc<Lease<Buffer>>),
102 Image(Arc<Image>),
103 ImageArg(ImageInfo),
104 ImageLease(Arc<Lease<Image>>),
105 SwapchainImage(Box<SwapchainImage>),
106}
107
108impl Clone for AnyResource {
109 fn clone(&self) -> Self {
110 match self {
111 Self::AccelerationStructure(resource) => {
112 Self::AccelerationStructure(Arc::clone(resource))
113 }
114 Self::AccelerationStructureArg(info) => Self::AccelerationStructureArg(*info),
115 Self::AccelerationStructureLease(resource) => {
116 Self::AccelerationStructureLease(Arc::clone(resource))
117 }
118 Self::Buffer(resource) => Self::Buffer(Arc::clone(resource)),
119 Self::BufferArg(info) => Self::BufferArg(*info),
120 Self::BufferLease(resource) => Self::BufferLease(Arc::clone(resource)),
121 Self::Image(resource) => Self::Image(Arc::clone(resource)),
122 Self::ImageArg(info) => Self::ImageArg(*info),
123 Self::ImageLease(resource) => Self::ImageLease(Arc::clone(resource)),
124 Self::SwapchainImage(resource) => {
125 Self::SwapchainImage(Box::new(unsafe { resource.to_detached() }))
126 }
127 }
128 }
129}
130
131macro_rules! any_resource_from_arc {
132 ($name:ident) => {
133 paste::paste! {
134 impl From<Arc<$name>> for AnyResource {
135 fn from(resource: Arc<$name>) -> Self {
136 Self::$name(resource)
137 }
138 }
139
140 impl From<Arc<Lease<$name>>> for AnyResource {
141 fn from(resource: Arc<Lease<$name>>) -> Self {
142 Self::[<$name Lease>](resource)
143 }
144 }
145 }
146 };
147}
148
149any_resource_from_arc!(AccelerationStructure);
150any_resource_from_arc!(Buffer);
151any_resource_from_arc!(Image);
152
153impl AnyResource {
154 fn as_accel_struct(&self) -> Option<&AccelerationStructure> {
155 Some(match self {
156 Self::AccelerationStructure(resource) => resource,
157 Self::AccelerationStructureLease(resource) => resource,
158 _ => return None,
159 })
160 }
161
162 fn as_buffer(&self) -> Option<&Buffer> {
163 Some(match self {
164 Self::Buffer(resource) => resource,
165 Self::BufferLease(resource) => resource,
166 _ => return None,
167 })
168 }
169
170 fn as_image(&self) -> Option<&Image> {
171 Some(match self {
172 Self::Image(resource) => resource,
173 Self::ImageLease(resource) => resource,
174 Self::SwapchainImage(resource) => resource,
175 _ => return None,
176 })
177 }
178
179 fn expect_accel_struct(&self) -> &AccelerationStructure {
180 self.as_accel_struct()
181 .expect("missing acceleration structure resource")
182 }
183
184 pub(crate) fn expect_accel_struct_info(
185 &self,
186 ) -> crate::driver::accel_struct::AccelerationStructureInfo {
187 match self {
188 Self::AccelerationStructure(resource) => resource.info,
189 Self::AccelerationStructureArg(info) => *info,
190 Self::AccelerationStructureLease(resource) => resource.info,
191 _ => panic!("missing acceleration structure resource"),
192 }
193 }
194
195 fn expect_buffer(&self) -> &Buffer {
196 self.as_buffer().expect("missing buffer resource")
197 }
198
199 pub(crate) fn expect_buffer_info(&self) -> crate::driver::buffer::BufferInfo {
200 match self {
201 Self::Buffer(resource) => resource.info,
202 Self::BufferArg(info) => *info,
203 Self::BufferLease(resource) => resource.info,
204 _ => panic!("missing buffer resource"),
205 }
206 }
207
208 fn expect_image(&self) -> &Image {
209 self.as_image().expect("missing image resource")
210 }
211
212 pub(crate) fn expect_image_info(&self) -> ImageInfo {
213 match self {
214 Self::Image(resource) => resource.info,
215 Self::ImageArg(info) => *info,
216 Self::ImageLease(resource) => resource.info,
217 Self::SwapchainImage(resource) => resource.info,
218 _ => panic!("missing image resource"),
219 }
220 }
221}
222
223#[derive(Clone, Copy, Debug)]
224struct Attachment {
225 array_layer_count: u32,
226 aspect_mask: vk::ImageAspectFlags,
227 base_array_layer: u32,
228 base_mip_level: u32,
229 format: vk::Format,
230 mip_level_count: u32,
231 sample_count: SampleCount,
232 target: NodeIndex,
233}
234
235impl Attachment {
236 fn new(image_view_info: ImageViewInfo, sample_count: SampleCount, target: NodeIndex) -> Self {
237 Self {
238 array_layer_count: image_view_info.array_layer_count,
239 aspect_mask: image_view_info.aspect_mask,
240 base_array_layer: image_view_info.base_array_layer,
241 base_mip_level: image_view_info.base_mip_level,
242 format: image_view_info.format,
243 mip_level_count: image_view_info.mip_level_count,
244 sample_count,
245 target,
246 }
247 }
248
249 fn are_compatible(lhs: Option<Self>, rhs: Option<Self>) -> bool {
250 let (Some(lhs), Some(rhs)) = (lhs, rhs) else {
254 return true;
255 };
256
257 Self::are_identical(lhs, rhs)
258 }
259
260 fn are_identical(lhs: Self, rhs: Self) -> bool {
261 lhs.array_layer_count == rhs.array_layer_count
262 && lhs.base_array_layer == rhs.base_array_layer
263 && lhs.base_mip_level == rhs.base_mip_level
264 && lhs.format == rhs.format
265 && lhs.mip_level_count == rhs.mip_level_count
266 && lhs.sample_count == rhs.sample_count
267 && lhs.target == rhs.target
268 }
269
270 fn image_view_info(self, image_info: ImageInfo) -> ImageViewInfo {
271 image_info
272 .into_builder()
273 .array_layer_count(self.array_layer_count)
274 .mip_level_count(self.mip_level_count)
275 .format(self.format)
276 .into_image_view()
277 .aspect_mask(self.aspect_mask)
278 .base_array_layer(self.base_array_layer)
279 .base_mip_level(self.base_mip_level)
280 .build()
281 }
282
283 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
284 self.target = node_map[self.target];
285 }
286}
287
288#[derive(Clone, Copy, Debug)]
289struct ColorAttachment {
290 attachment: Attachment,
291 load: LoadOp<[f32; 4]>,
292 store: StoreOp,
293 resolve: Option<ColorResolve>,
294 is_input: bool,
295 is_attachment: bool,
296}
297
298#[derive(Clone, Debug, Default)]
299struct ExecutionAttachmentMap {
300 color: Vec<Option<ColorAttachment>>,
301 depth_stencil: Option<DepthStencilAttachment>,
302}
303
304impl ExecutionAttachmentMap {
305 fn color_attachment(&self, attachment_idx: AttachmentIndex) -> Option<&ColorAttachment> {
306 self.color
307 .get(attachment_idx as usize)
308 .and_then(|slot| slot.as_ref())
309 }
310
311 fn color_attachment_mut(
312 &mut self,
313 attachment_idx: AttachmentIndex,
314 ) -> Option<&mut ColorAttachment> {
315 self.color
316 .get_mut(attachment_idx as usize)
317 .and_then(|slot| slot.as_mut())
318 }
319
320 fn color_attachments(&self) -> impl Iterator<Item = (AttachmentIndex, &ColorAttachment)> + '_ {
321 self.color
322 .iter()
323 .enumerate()
324 .filter_map(|(attachment_idx, slot)| {
325 Some((attachment_idx as AttachmentIndex, slot.as_ref()?))
326 })
327 }
328
329 fn depth_stencil_attachment(&self) -> Option<&DepthStencilAttachment> {
330 self.depth_stencil.as_ref()
331 }
332
333 fn depth_stencil_attachment_mut(&mut self) -> Option<&mut DepthStencilAttachment> {
334 self.depth_stencil.as_mut()
335 }
336
337 fn set_color_attachment(
338 &mut self,
339 attachment_idx: AttachmentIndex,
340 attachment: ColorAttachment,
341 ) {
342 let attachment_idx = attachment_idx as usize;
343
344 if self.color.len() <= attachment_idx {
345 self.color.resize(attachment_idx + 1, None);
346 }
347
348 #[cfg(feature = "checked")]
349 {
350 let existing_attachment = self.color[attachment_idx]
351 .as_ref()
352 .map(|&color| color.attachment);
353
354 assert!(
355 Attachment::are_compatible(existing_attachment, Some(attachment.attachment)),
356 "incompatible with existing attachment"
357 );
358 }
359
360 self.color[attachment_idx] = Some(attachment);
361 }
362
363 fn set_depth_stencil_attachment(&mut self, attachment: DepthStencilAttachment) {
364 #[cfg(feature = "checked")]
365 {
366 let existing_attachment = self
367 .depth_stencil
368 .as_ref()
369 .map(|&depth_stencil| depth_stencil.attachment);
370
371 assert!(
372 Attachment::are_compatible(existing_attachment, Some(attachment.attachment)),
373 "incompatible with existing attachment"
374 );
375 }
376
377 self.depth_stencil = Some(attachment);
378 }
379
380 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
381 for attachment in self.color.iter_mut().flatten() {
382 attachment.attachment.remap_nodes(node_map);
383
384 if let Some(resolve) = &mut attachment.resolve {
385 resolve.attachment.remap_nodes(node_map);
386 }
387 }
388
389 if let Some(attachment) = &mut self.depth_stencil {
390 attachment.attachment.remap_nodes(node_map);
391
392 if let Some(resolve) = &mut attachment.resolve {
393 resolve.attachment.remap_nodes(node_map);
394 }
395 }
396 }
397}
398
399#[derive(Clone, Copy, Debug)]
400struct ColorResolve {
401 attachment: Attachment,
402 src_attachment_idx: AttachmentIndex,
403}
404
405#[derive(Clone, Debug)]
406struct CommandData {
407 execs: Vec<Execution>,
408
409 #[cfg(debug_assertions)]
410 name: Option<String>,
411
412 stream_scope_id: Option<u64>,
413}
414
415impl CommandData {
416 fn descriptor_pools_sizes(
417 &self,
418 ) -> impl Iterator<Item = impl Iterator<Item = (&vk::DescriptorType, &u32)>> {
419 self.execs
420 .iter()
421 .flat_map(|exec| &exec.pipeline)
422 .map(|pipeline| {
423 pipeline
424 .descriptor_info()
425 .pool_sizes
426 .values()
427 .flat_map(HashMap::iter)
428 })
429 }
430
431 fn expect_first_exec(&self) -> &Execution {
432 self.execs.first().expect("missing command execution")
433 }
434
435 fn expect_last_exec(&self) -> &Execution {
439 self.execs.last().expect("missing command execution")
440 }
441
442 fn expect_last_exec_mut(&mut self) -> &mut Execution {
446 self.execs.last_mut().expect("missing command execution")
447 }
448
449 fn expect_last_pipeline(&self) -> &ExecutionPipeline {
450 self.expect_last_exec()
451 .pipeline
452 .as_ref()
453 .expect("missing command pipeline")
454 }
455
456 fn name(&self) -> &str {
457 const DEFAULT: &str = "command";
458
459 #[cfg(debug_assertions)]
460 {
461 self.name.as_deref().unwrap_or(DEFAULT)
462 }
463
464 #[cfg(not(debug_assertions))]
465 {
466 DEFAULT
467 }
468 }
469
470 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
471 for exec in &mut self.execs {
472 exec.remap_nodes(node_map);
473 }
474 }
475}
476
477enum CommandFunction {
478 Once(CommandFnOnce),
479 Reusable(CommandFn),
480}
481
482impl CommandFunction {
483 fn is_reusable(&self) -> bool {
484 matches!(self, Self::Reusable(_))
485 }
486
487 fn record(self, cmd: CommandRef<'_>) -> Option<Self> {
488 match self {
489 Self::Once(func) => {
490 func(cmd);
491 None
492 }
493 Self::Reusable(func) => {
494 func(cmd);
495 Some(Self::Reusable(func))
496 }
497 }
498 }
499}
500
501impl Clone for CommandFunction {
502 fn clone(&self) -> Self {
503 match self {
504 Self::Once(_) => panic!("one-shot command callback cannot be cloned"),
505 Self::Reusable(func) => Self::Reusable(Arc::clone(func)),
506 }
507 }
508}
509
510#[derive(Clone, Copy, Debug)]
511struct DepthStencilAttachment {
512 attachment: Attachment,
513 load: LoadOp<vk::ClearDepthStencilValue>,
514 store: StoreOp,
515 resolve: Option<DepthStencilResolve>,
516 is_attachment: bool,
517}
518
519#[derive(Clone, Copy, Debug)]
520struct DepthStencilResolve {
521 attachment: Attachment,
522 dst_attachment_idx: AttachmentIndex,
523 depth_mode: Option<ResolveMode>,
524 stencil_mode: Option<ResolveMode>,
525}
526
527#[derive(Clone)]
528enum ExecutionAccess {
529 Building(ExecutionAccessBuilder),
530 Frozen(FrozenExecutionAccess),
531}
532
533impl ExecutionAccess {
534 fn contains(&self, node_idx: NodeIndex) -> bool {
535 match self {
536 Self::Building(builder) => builder.lookup.contains_key(&node_idx),
537 Self::Frozen(frozen) => frozen.lookup.contains_key(&node_idx),
538 }
539 }
540
541 fn freeze(&mut self) {
542 let Self::Building(builder) = mem::take(self) else {
543 return;
544 };
545
546 let ExecutionAccessBuilder { entries, lookup } = builder;
547 let entries = entries
548 .into_iter()
549 .map(|entry| NodeAccess {
550 node_idx: entry.node_idx,
551 accesses: entry.accesses.into_vec().into_boxed_slice(),
552 })
553 .collect();
554
555 *self = Self::Frozen(FrozenExecutionAccess { entries, lookup });
556 }
557
558 fn get_mut(&mut self, node_idx: &NodeIndex) -> Option<&mut [SubresourceAccess]> {
559 let Self::Building(builder) = self else {
560 panic!("execution accesses are frozen")
561 };
562
563 builder
564 .lookup
565 .get(node_idx)
566 .copied()
567 .map(|entry_idx| builder.entries[entry_idx].accesses.as_mut_slice())
568 }
569
570 fn iter(&self) -> ExecutionAccessIter<'_> {
571 match self {
572 Self::Building(builder) => ExecutionAccessIter::Building(builder.entries.iter()),
573 Self::Frozen(frozen) => ExecutionAccessIter::Frozen(frozen.entries.iter()),
574 }
575 }
576
577 fn push(&mut self, node_idx: NodeIndex, access: SubresourceAccess) {
578 let Self::Building(builder) = self else {
579 panic!("execution accesses are frozen")
580 };
581
582 let idx = *builder.lookup.entry(node_idx).or_insert_with(|| {
583 let idx = builder.entries.len();
584 builder.entries.push(NodeAccessBuilder {
585 node_idx,
586 accesses: Default::default(),
587 });
588
589 idx
590 });
591 builder.entries[idx].accesses.push(access);
592 }
593
594 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
595 match self {
596 Self::Building(builder) => {
597 for entry in &mut builder.entries {
598 entry.node_idx = node_map[entry.node_idx];
599 }
600
601 builder.lookup = builder
602 .entries
603 .iter()
604 .enumerate()
605 .map(|(idx, entry)| (entry.node_idx, idx))
606 .collect();
607 }
608 Self::Frozen(frozen) => {
609 for entry in frozen.entries.iter_mut() {
610 entry.node_idx = node_map[entry.node_idx];
611 }
612
613 frozen.lookup = frozen
614 .entries
615 .iter()
616 .enumerate()
617 .map(|(idx, entry)| (entry.node_idx, idx))
618 .collect();
619 }
620 }
621 }
622}
623
624impl Debug for ExecutionAccess {
625 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
626 match self {
627 Self::Building(builder) => builder.entries.fmt(f),
628 Self::Frozen(frozen) => frozen.entries.fmt(f),
629 }
630 }
631}
632
633impl Default for ExecutionAccess {
634 fn default() -> Self {
635 Self::Building(Default::default())
636 }
637}
638
639#[derive(Clone, Debug, Default)]
640struct ExecutionAccessBuilder {
641 entries: Vec<NodeAccessBuilder>,
642 lookup: HashMap<NodeIndex, usize>,
643}
644
645enum ExecutionAccessIter<'a> {
646 Building(Iter<'a, NodeAccessBuilder>),
647 Frozen(Iter<'a, NodeAccess>),
648}
649
650impl<'a> Iterator for ExecutionAccessIter<'a> {
651 type Item = (NodeIndex, &'a [SubresourceAccess]);
652
653 fn next(&mut self) -> Option<Self::Item> {
654 match self {
655 ExecutionAccessIter::Building(iter) => iter
656 .next()
657 .map(|entry| (entry.node_idx, entry.accesses.as_slice())),
658 ExecutionAccessIter::Frozen(iter) => iter
659 .next()
660 .map(|entry| (entry.node_idx, entry.accesses.as_ref())),
661 }
662 }
663
664 fn size_hint(&self) -> (usize, Option<usize>) {
665 let len = self.len();
666
667 (len, Some(len))
668 }
669}
670
671impl ExactSizeIterator for ExecutionAccessIter<'_> {
672 fn len(&self) -> usize {
673 match self {
674 ExecutionAccessIter::Building(iter) => iter.len(),
675 ExecutionAccessIter::Frozen(iter) => iter.len(),
676 }
677 }
678}
679
680#[derive(Clone, Default)]
681struct Execution {
682 accesses: ExecutionAccess,
683 attachments: ExecutionAttachmentMap,
684 bindings: BTreeMap<Binding, (NodeIndex, ViewInfo)>,
685
686 correlated_view_mask: u32,
687 depth_stencil: Option<DepthStencilInfo>,
688 render_area: Option<vk::Rect2D>,
689 view_mask: u32,
690
691 func: Option<CommandFunction>,
692 node_map: Option<Arc<[NodeIndex]>>,
693 pipeline: Option<ExecutionPipeline>,
694
695 #[cfg(feature = "checked")]
696 stream_graph_id: Option<GraphId>,
697}
698
699impl Execution {
700 fn remap_nodes(&mut self, node_map: &[NodeIndex]) {
701 let original_node_map = Arc::<[NodeIndex]>::from(node_map.to_vec());
702 self.accesses.remap_nodes(node_map);
703 self.attachments.remap_nodes(node_map);
704
705 self.bindings = mem::take(&mut self.bindings)
706 .into_iter()
707 .map(|(binding, (node_idx, view))| (binding, (node_map[node_idx], view)))
708 .collect();
709 self.node_map = Some(original_node_map);
710 }
711}
712
713impl Debug for Execution {
714 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
715 f.debug_struct("Execution")
718 .field("accesses", &self.accesses)
719 .field("attachments", &self.attachments)
720 .field("bindings", &self.bindings)
721 .field("correlated_view_mask", &self.correlated_view_mask)
722 .field("depth_stencil", &self.depth_stencil)
723 .field("render_area", &self.render_area)
724 .field("view_mask", &self.view_mask)
725 .field("pipeline", &self.pipeline)
726 .finish()
727 }
728}
729
730#[derive(Clone, Debug)]
731enum ExecutionPipeline {
732 Compute(ComputePipeline),
733 Graphics(GraphicsPipeline),
734 RayTracing(RayTracingPipeline),
735}
736
737impl ExecutionPipeline {
738 fn as_graphics(&self) -> Option<&GraphicsPipeline> {
739 if let Self::Graphics(pipeline) = self {
740 Some(pipeline)
741 } else {
742 None
743 }
744 }
745
746 fn bind_point(&self) -> vk::PipelineBindPoint {
747 match self {
748 ExecutionPipeline::Compute(_) => vk::PipelineBindPoint::COMPUTE,
749 ExecutionPipeline::Graphics(_) => vk::PipelineBindPoint::GRAPHICS,
750 ExecutionPipeline::RayTracing(_) => vk::PipelineBindPoint::RAY_TRACING_KHR,
751 }
752 }
753
754 fn descriptor_bindings(&self) -> &DescriptorBindingMap {
755 match self {
756 ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_bindings,
757 ExecutionPipeline::Graphics(pipeline) => &pipeline.inner.descriptor_bindings,
758 ExecutionPipeline::RayTracing(pipeline) => &pipeline.inner.descriptor_bindings,
759 }
760 }
761
762 fn descriptor_info(&self) -> &PipelineDescriptorInfo {
763 match self {
764 ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_info,
765 ExecutionPipeline::Graphics(pipeline) => &pipeline.inner.descriptor_info,
766 ExecutionPipeline::RayTracing(pipeline) => &pipeline.inner.descriptor_info,
767 }
768 }
769
770 fn expect_compute(&self) -> &ComputePipeline {
771 if let Self::Compute(pipeline) = self {
772 pipeline
773 } else {
774 panic!("missing compute pipeline")
775 }
776 }
777
778 fn expect_graphics(&self) -> &GraphicsPipeline {
779 self.as_graphics().expect("missing graphics pipeline")
780 }
781
782 fn expect_ray_tracing(&self) -> &RayTracingPipeline {
783 if let Self::RayTracing(pipeline) = self {
784 pipeline
785 } else {
786 panic!("missing ray tracing pipeline")
787 }
788 }
789
790 fn layout(&self) -> vk::PipelineLayout {
791 match self {
792 ExecutionPipeline::Compute(pipeline) => pipeline.inner.layout,
793 ExecutionPipeline::Graphics(pipeline) => pipeline.inner.layout,
794 ExecutionPipeline::RayTracing(pipeline) => pipeline.inner.layout,
795 }
796 }
797}
798
799#[derive(Clone, Debug)]
800struct FrozenExecutionAccess {
801 entries: Box<[NodeAccess]>,
802 lookup: HashMap<NodeIndex, usize>,
803}
804
805#[derive(Debug)]
814pub struct Graph {
815 cmds: Vec<CommandData>,
816 resources: ResourceMap,
817
818 #[cfg(feature = "checked")]
819 graph_id: GraphId,
820}
821
822impl Default for Graph {
823 fn default() -> Self {
824 Self {
825 cmds: Default::default(),
826 resources: Default::default(),
827
828 #[cfg(feature = "checked")]
829 graph_id: GraphId::next(),
830 }
831 }
832}
833
834impl Graph {
835 pub fn new() -> Self {
837 Self::default()
838 }
839
840 pub(crate) fn assert_node_owner<N>(&self, _resource_node: &N)
841 where
842 N: Node,
843 {
844 #[cfg(feature = "checked")]
845 _resource_node.assert_owner(self.graph_id);
846 }
847
848 #[cfg(feature = "checked")]
849 pub(crate) fn graph_id(&self) -> GraphId {
850 self.graph_id
851 }
852
853 pub fn begin_cmd(&mut self) -> Command<'_> {
855 Command::new(self)
856 }
857
858 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
863 where
864 R: Resource,
865 {
866 resource.bind_graph(self)
867 }
868
869 pub(crate) fn bind_stream_arg_resource(&mut self, resource: AnyResource) -> NodeIndex {
870 self.resources.bind(resource)
871 }
872
873 pub fn blit_image(
880 &mut self,
881 src: impl Into<AnyImageNode>,
882 dst: impl Into<AnyImageNode>,
883 filter: vk::Filter,
884 ) -> &mut Self {
885 let src = src.into();
886 let src_info = self.resources[src.index()].expect_image_info();
887
888 let dst = dst.into();
889 let dst_info = self.resources[dst.index()].expect_image_info();
890
891 self.blit_image_region(
892 src,
893 dst,
894 filter,
895 [vk::ImageBlit {
896 src_subresource: vk::ImageSubresourceLayers {
897 aspect_mask: format_aspect_mask(src_info.format),
898 mip_level: 0,
899 base_array_layer: 0,
900 layer_count: 1,
901 },
902 src_offsets: [
903 vk::Offset3D { x: 0, y: 0, z: 0 },
904 vk::Offset3D {
905 x: src_info.width as _,
906 y: src_info.height as _,
907 z: src_info.depth as _,
908 },
909 ],
910 dst_subresource: vk::ImageSubresourceLayers {
911 aspect_mask: format_aspect_mask(dst_info.format),
912 mip_level: 0,
913 base_array_layer: 0,
914 layer_count: 1,
915 },
916 dst_offsets: [
917 vk::Offset3D { x: 0, y: 0, z: 0 },
918 vk::Offset3D {
919 x: dst_info.width as _,
920 y: dst_info.height as _,
921 z: dst_info.depth as _,
922 },
923 ],
924 }],
925 )
926 }
927
928 #[profiling::function]
935 pub fn blit_image_region(
936 &mut self,
937 src: impl Into<AnyImageNode>,
938 dst: impl Into<AnyImageNode>,
939 filter: vk::Filter,
940 regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
941 ) -> &mut Self {
942 let src = src.into();
943 let dst = dst.into();
944 let regions = Arc::<[vk::ImageBlit]>::from(regions.as_ref());
945
946 let mut cmd = self.begin_cmd().debug_name("blit image");
947
948 for region in regions.as_ref() {
949 let src_region = image_subresource_range_from_layers(region.src_subresource);
950 cmd.set_subresource_access(src, src_region, AccessType::TransferRead);
951
952 let dst_region = image_subresource_range_from_layers(region.dst_subresource);
953 cmd.set_subresource_access(dst, dst_region, AccessType::TransferWrite);
954 }
955
956 cmd.record_stream(move |cmd| {
957 let src_image = cmd.resource(src).handle;
958 let dst_image = cmd.resource(dst).handle;
959
960 unsafe {
961 cmd.device.cmd_blit_image(
962 cmd.handle,
963 src_image,
964 vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
965 dst_image,
966 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
967 regions.as_ref(),
968 filter,
969 );
970 }
971 })
972 .end_cmd()
973 }
974
975 #[profiling::function]
982 pub fn clear_color_image(
983 &mut self,
984 image: impl Into<AnyImageNode>,
985 color: impl Into<ClearColorValue>,
986 ) -> &mut Self {
987 let color = color.into().into();
988 let image = image.into();
989 let image_view = self.resources[image.index()].expect_image_info().into();
990
991 self.begin_cmd()
992 .debug_name("clear color")
993 .subresource_access(image, image_view, AccessType::TransferWrite)
994 .record_stream(move |cmd| {
995 let image = cmd.resource(image);
996
997 unsafe {
998 cmd.device.cmd_clear_color_image(
999 cmd.handle,
1000 image.handle,
1001 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
1002 &color,
1003 &[image_view],
1004 );
1005 }
1006 })
1007 .end_cmd()
1008 }
1009
1010 #[profiling::function]
1017 pub fn clear_depth_stencil_image(
1018 &mut self,
1019 image: impl Into<AnyImageNode>,
1020 depth: f32,
1021 stencil: u32,
1022 ) -> &mut Self {
1023 let image = image.into();
1024 let image_view = self.resources[image.index()].expect_image_info().into();
1025
1026 self.begin_cmd()
1027 .debug_name("clear depth/stencil")
1028 .subresource_access(image, image_view, AccessType::TransferWrite)
1029 .record_stream(move |cmd| {
1030 let image = cmd.resource(image);
1031
1032 unsafe {
1033 cmd.device.cmd_clear_depth_stencil_image(
1034 cmd.handle,
1035 image.handle,
1036 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
1037 &vk::ClearDepthStencilValue { depth, stencil },
1038 &[image_view],
1039 );
1040 }
1041 })
1042 .end_cmd()
1043 }
1044
1045 pub fn copy_buffer(
1052 &mut self,
1053 src: impl Into<AnyBufferNode>,
1054 dst: impl Into<AnyBufferNode>,
1055 ) -> &mut Self {
1056 let src = src.into();
1057 let dst = dst.into();
1058 let src_info = self.resources[src.index()].expect_buffer_info();
1059 let dst_info = self.resources[dst.index()].expect_buffer_info();
1060
1061 self.copy_buffer_region(
1062 src,
1063 dst,
1064 [vk::BufferCopy {
1065 src_offset: 0,
1066 dst_offset: 0,
1067 size: src_info.size.min(dst_info.size),
1068 }],
1069 )
1070 }
1071
1072 #[profiling::function]
1079 pub fn copy_buffer_region(
1080 &mut self,
1081 src: impl Into<AnyBufferNode>,
1082 dst: impl Into<AnyBufferNode>,
1083 regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
1084 ) -> &mut Self {
1085 let src = src.into();
1086 let dst = dst.into();
1087 let regions = Arc::<[vk::BufferCopy]>::from(regions.as_ref());
1088
1089 #[cfg(feature = "checked")]
1090 let src_size = self.resources[src.index()].expect_buffer_info().size;
1091
1092 #[cfg(feature = "checked")]
1093 let dst_size = self.resources[dst.index()].expect_buffer_info().size;
1094
1095 let mut cmd = self.begin_cmd().debug_name("copy buffer");
1096
1097 for region in regions.iter() {
1098 #[cfg(feature = "checked")]
1099 {
1100 assert!(
1101 region.src_offset + region.size <= src_size,
1102 "source range end ({}) exceeds source size ({src_size})",
1103 region.src_offset + region.size
1104 );
1105 assert!(
1106 region.dst_offset + region.size <= dst_size,
1107 "destination range end ({}) exceeds destination size ({dst_size})",
1108 region.dst_offset + region.size
1109 );
1110 };
1111
1112 cmd.set_subresource_access(
1113 src,
1114 region.src_offset..region.src_offset + region.size,
1115 AccessType::TransferRead,
1116 );
1117 cmd.set_subresource_access(
1118 dst,
1119 region.dst_offset..region.dst_offset + region.size,
1120 AccessType::TransferWrite,
1121 );
1122 }
1123
1124 cmd.record_stream(move |cmd| {
1125 let src = cmd.resource(src);
1126 let dst = cmd.resource(dst);
1127
1128 unsafe {
1129 cmd.device
1130 .cmd_copy_buffer(cmd.handle, src.handle, dst.handle, ®ions);
1131 }
1132 })
1133 .end_cmd()
1134 }
1135
1136 pub fn copy_buffer_to_image(
1142 &mut self,
1143 src: impl Into<AnyBufferNode>,
1144 dst: impl Into<AnyImageNode>,
1145 ) -> &mut Self {
1146 let dst = dst.into();
1147 let dst_info = self.resources[dst.index()].expect_image_info();
1148
1149 self.copy_buffer_to_image_region(
1150 src,
1151 dst,
1152 [vk::BufferImageCopy {
1153 buffer_offset: 0,
1154 buffer_row_length: dst_info.width,
1155 buffer_image_height: dst_info.height,
1156 image_subresource: vk::ImageSubresourceLayers {
1157 aspect_mask: format_aspect_mask(dst_info.format),
1158 mip_level: 0,
1159 base_array_layer: 0,
1160 layer_count: 1,
1161 },
1162 image_offset: Default::default(),
1163 image_extent: vk::Extent3D {
1164 depth: dst_info.depth,
1165 height: dst_info.height,
1166 width: dst_info.width,
1167 },
1168 }],
1169 )
1170 }
1171
1172 #[profiling::function]
1179 pub fn copy_buffer_to_image_region(
1180 &mut self,
1181 src: impl Into<AnyBufferNode>,
1182 dst: impl Into<AnyImageNode>,
1183 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1184 ) -> &mut Self {
1185 let src = src.into();
1186 let dst = dst.into();
1187 let dst_info = self.resources[dst.index()].expect_image_info();
1188 let regions = Arc::<[vk::BufferImageCopy]>::from(regions.as_ref());
1189
1190 let mut cmd = self.begin_cmd().debug_name("copy buffer to image");
1191
1192 for region in regions.iter() {
1193 let block_bytes_size = format_texel_block_size(dst_info.format);
1194 let (block_height, block_width) = format_texel_block_extent(dst_info.format);
1195 let data_size = block_bytes_size
1196 * (region.buffer_row_length / block_width)
1197 * (region.buffer_image_height / block_height);
1198
1199 cmd.set_subresource_access(
1200 src,
1201 region.buffer_offset..region.buffer_offset + data_size as vk::DeviceSize,
1202 AccessType::TransferRead,
1203 );
1204 cmd.set_subresource_access(
1205 dst,
1206 image_subresource_range_from_layers(region.image_subresource),
1207 AccessType::TransferWrite,
1208 );
1209 }
1210
1211 cmd.record_stream(move |cmd| {
1212 let src = cmd.resource(src);
1213 let dst = cmd.resource(dst);
1214
1215 unsafe {
1216 cmd.device.cmd_copy_buffer_to_image(
1217 cmd.handle,
1218 src.handle,
1219 dst.handle,
1220 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
1221 ®ions,
1222 );
1223 }
1224 })
1225 .end_cmd()
1226 }
1227
1228 pub fn copy_image(
1235 &mut self,
1236 src: impl Into<AnyImageNode>,
1237 dst: impl Into<AnyImageNode>,
1238 ) -> &mut Self {
1239 let src = src.into();
1240 let src_info = self.resources[src.index()].expect_image_info();
1241
1242 let dst = dst.into();
1243 let dst_info = self.resources[dst.index()].expect_image_info();
1244
1245 self.copy_image_region(
1246 src,
1247 dst,
1248 [vk::ImageCopy {
1249 src_subresource: vk::ImageSubresourceLayers {
1250 aspect_mask: format_aspect_mask(src_info.format),
1251 mip_level: 0,
1252 base_array_layer: 0,
1253 layer_count: src_info.array_layer_count,
1254 },
1255 src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1256 dst_subresource: vk::ImageSubresourceLayers {
1257 aspect_mask: format_aspect_mask(dst_info.format),
1258 mip_level: 0,
1259 base_array_layer: 0,
1260 layer_count: src_info.array_layer_count,
1261 },
1262 dst_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
1263 extent: vk::Extent3D {
1264 depth: src_info.depth.clamp(1, dst_info.depth),
1265 height: src_info.height.clamp(1, dst_info.height),
1266 width: src_info.width.min(dst_info.width),
1267 },
1268 }],
1269 )
1270 }
1271
1272 #[profiling::function]
1279 pub fn copy_image_region(
1280 &mut self,
1281 src: impl Into<AnyImageNode>,
1282 dst: impl Into<AnyImageNode>,
1283 regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
1284 ) -> &mut Self {
1285 let src = src.into();
1286 let dst = dst.into();
1287 let regions = Arc::<[vk::ImageCopy]>::from(regions.as_ref());
1288
1289 let mut cmd = self.begin_cmd().debug_name("copy image");
1290
1291 for region in regions.iter() {
1292 cmd.set_subresource_access(
1293 src,
1294 image_subresource_range_from_layers(region.src_subresource),
1295 AccessType::TransferRead,
1296 );
1297 cmd.set_subresource_access(
1298 dst,
1299 image_subresource_range_from_layers(region.dst_subresource),
1300 AccessType::TransferWrite,
1301 );
1302 }
1303
1304 cmd.record_stream(move |cmd| {
1305 let src = cmd.resource(src);
1306 let dst = cmd.resource(dst);
1307
1308 unsafe {
1309 cmd.device.cmd_copy_image(
1310 cmd.handle,
1311 src.handle,
1312 vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
1313 dst.handle,
1314 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
1315 ®ions,
1316 );
1317 }
1318 })
1319 .end_cmd()
1320 }
1321
1322 pub fn copy_image_to_buffer(
1328 &mut self,
1329 src: impl Into<AnyImageNode>,
1330 dst: impl Into<AnyBufferNode>,
1331 ) -> &mut Self {
1332 let src = src.into();
1333 let dst = dst.into();
1334
1335 let src_info = self.resources[src.index()].expect_image_info();
1336
1337 self.copy_image_to_buffer_region(
1338 src,
1339 dst,
1340 [vk::BufferImageCopy {
1341 buffer_offset: 0,
1342 buffer_row_length: src_info.width,
1343 buffer_image_height: src_info.height,
1344 image_subresource: vk::ImageSubresourceLayers {
1345 aspect_mask: format_aspect_mask(src_info.format),
1346 mip_level: 0,
1347 base_array_layer: 0,
1348 layer_count: 1,
1349 },
1350 image_offset: Default::default(),
1351 image_extent: vk::Extent3D {
1352 depth: src_info.depth,
1353 height: src_info.height,
1354 width: src_info.width,
1355 },
1356 }],
1357 )
1358 }
1359
1360 #[profiling::function]
1367 pub fn copy_image_to_buffer_region(
1368 &mut self,
1369 src: impl Into<AnyImageNode>,
1370 dst: impl Into<AnyBufferNode>,
1371 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1372 ) -> &mut Self {
1373 let src = src.into();
1374 let src_info = self.resources[src.index()].expect_image_info();
1375 let dst = dst.into();
1376 let regions = Arc::<[vk::BufferImageCopy]>::from(regions.as_ref());
1377
1378 let mut cmd = self.begin_cmd().debug_name("copy image to buffer");
1379
1380 for region in regions.iter() {
1381 let block_bytes_size = format_texel_block_size(src_info.format);
1382 let (block_height, block_width) = format_texel_block_extent(src_info.format);
1383 let data_size = block_bytes_size
1384 * (region.buffer_row_length / block_width)
1385 * (region.buffer_image_height / block_height);
1386
1387 cmd.set_subresource_access(
1388 src,
1389 image_subresource_range_from_layers(region.image_subresource),
1390 AccessType::TransferRead,
1391 );
1392 cmd.set_subresource_access(
1393 dst,
1394 region.buffer_offset..region.buffer_offset + data_size as vk::DeviceSize,
1395 AccessType::TransferWrite,
1396 );
1397 }
1398
1399 cmd.record_stream(move |cmd| {
1400 let src = cmd.resource(src);
1401 let dst = cmd.resource(dst);
1402
1403 unsafe {
1404 cmd.device.cmd_copy_image_to_buffer(
1405 cmd.handle,
1406 src.handle,
1407 vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
1408 dst.handle,
1409 ®ions,
1410 );
1411 }
1412 })
1413 .end_cmd()
1414 }
1415
1416 pub fn fill_buffer(
1422 &mut self,
1423 buffer: impl Into<AnyBufferNode>,
1424 region: Range<vk::DeviceSize>,
1425 data: u32,
1426 ) -> &mut Self {
1427 let buffer = buffer.into();
1428
1429 self.begin_cmd()
1430 .debug_name("fill buffer")
1431 .subresource_access(buffer, region.clone(), AccessType::TransferWrite)
1432 .record_stream(move |cmd| {
1433 let buffer = cmd.resource(buffer);
1434
1435 unsafe {
1436 cmd.device.cmd_fill_buffer(
1437 cmd.handle,
1438 buffer.handle,
1439 region.start,
1440 region.end - region.start,
1441 data,
1442 );
1443 }
1444 })
1445 .end_cmd()
1446 }
1447
1448 #[profiling::function]
1450 fn first_node_access_pass_index(&self, resource_node: impl Node) -> Option<usize> {
1451 self.assert_node_owner(&resource_node);
1452
1453 let node_idx = resource_node.index();
1454
1455 for (pass_idx, pass) in self.cmds.iter().enumerate() {
1456 for exec in pass.execs.iter() {
1457 if exec.accesses.contains(node_idx) {
1458 return Some(pass_idx);
1459 }
1460 }
1461 }
1462
1463 None
1464 }
1465
1466 #[profiling::function]
1469 pub fn finalize(mut self) -> Submission {
1470 for cmd in &mut self.cmds {
1472 debug_assert!(cmd.expect_last_exec().func.is_none());
1473
1474 cmd.execs.pop();
1475
1476 for exec in &mut cmd.execs {
1477 exec.accesses.freeze();
1478 }
1479 }
1480
1481 Submission::new(self)
1482 }
1483
1484 pub fn resource<N>(&self, resource_node: N) -> &N::Resource
1501 where
1502 N: Node,
1503 {
1504 self.assert_node_owner(&resource_node);
1505 resource_node.borrow(&self.resources)
1506 }
1507
1508 #[profiling::function]
1517 pub fn update_buffer(
1518 &mut self,
1519 buffer: impl Into<AnyBufferNode>,
1520 offset: vk::DeviceSize,
1521 data: impl AsRef<[u8]> + 'static + Send,
1522 ) -> &mut Self {
1523 debug_assert!(data.as_ref().len() <= 64 * 1024);
1524
1525 let buffer = buffer.into();
1526 let data_end = offset + data.as_ref().len() as vk::DeviceSize;
1527
1528 #[cfg(feature = "checked")]
1529 {
1530 assert!(
1531 data.as_ref().len() <= 64 * 1024,
1532 "data length ({}) exceeds vkCmdUpdateBuffer limit (65536)",
1533 data.as_ref().len()
1534 );
1535
1536 let buffer_info = self.resources[buffer.index()].expect_buffer_info();
1537
1538 assert!(
1539 data_end <= buffer_info.size,
1540 "data range end ({data_end}) exceeds buffer size ({})",
1541 buffer_info.size
1542 );
1543 }
1544
1545 let data = Arc::<[u8]>::from(data.as_ref());
1546
1547 self.begin_cmd()
1548 .debug_name("update buffer")
1549 .subresource_access(buffer, offset..data_end, AccessType::TransferWrite)
1550 .record_stream(move |cmd| {
1551 let buffer = cmd.resource(buffer);
1552
1553 unsafe {
1554 cmd.device
1555 .cmd_update_buffer(cmd.handle, buffer.handle, offset, &data);
1556 }
1557 })
1558 .end_cmd()
1559 }
1560}
1561
1562#[derive(Clone, Copy, Debug)]
1567pub enum LoadOp<T> {
1568 Clear(T),
1573
1574 DontCare,
1576
1577 Load,
1579}
1580
1581#[allow(private_bounds)]
1587pub trait Node: private::NodeSealed {
1588 type Resource;
1590
1591 type SyncInfo;
1593
1594 #[doc(hidden)]
1595 fn index(&self) -> usize;
1596}
1597
1598#[derive(Clone, Debug)]
1599struct NodeAccess {
1600 node_idx: NodeIndex,
1601 accesses: Box<[SubresourceAccess]>,
1602}
1603
1604#[derive(Clone, Debug)]
1605struct NodeAccessBuilder {
1606 node_idx: NodeIndex,
1607 accesses: SmallVec<[SubresourceAccess; 2]>,
1608}
1609
1610mod private {
1611 use super::{AnyResource, Node};
1612
1613 #[cfg(feature = "checked")]
1614 use super::GraphId;
1615
1616 pub(crate) trait NodeSealed: Sized {
1618 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource
1619 where
1620 Self: Node;
1621
1622 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource
1623 where
1624 Self: Node,
1625 {
1626 debug_assert_eq!(self.index(), index);
1627 self.borrow(resources)
1628 }
1629
1630 #[cfg(feature = "checked")]
1631 fn assert_owner(&self, _graph_id: GraphId) {}
1632 }
1633
1634 pub(crate) trait ResourceSealed {}
1636}
1637
1638#[allow(private_bounds)]
1645pub trait Resource: private::ResourceSealed {
1646 type Node;
1648
1649 #[doc(hidden)]
1650 fn bind_graph(self, _: &mut Graph) -> Self::Node;
1651}
1652
1653impl private::ResourceSealed for SwapchainImage {}
1654
1655impl Resource for SwapchainImage {
1656 type Node = SwapchainImageNode;
1657
1658 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1659 let node = Self::Node::new(
1660 graph.resources.len(),
1661 #[cfg(feature = "checked")]
1662 graph.graph_id,
1663 );
1664
1665 let resource = AnyResource::SwapchainImage(Box::new(self));
1668 graph.resources.bind(resource);
1669
1670 node
1671 }
1672}
1673
1674macro_rules! resource {
1675 ($name:ident) => {
1676 paste::paste! {
1677 impl private::ResourceSealed for $name {}
1678 impl private::ResourceSealed for Arc<$name> {}
1679 impl<'a> private::ResourceSealed for &'a Arc<$name> {}
1680 impl private::ResourceSealed for Lease<$name> {}
1681 impl private::ResourceSealed for Arc<Lease<$name>> {}
1682 impl<'a> private::ResourceSealed for &'a Arc<Lease<$name>> {}
1683
1684 impl Resource for $name {
1685 type Node = [<$name Node>];
1686
1687 #[profiling::function]
1688 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1689 Arc::new(self).bind_graph(graph)
1693 }
1694 }
1695
1696 impl Resource for Arc<$name> {
1697 type Node = [<$name Node>];
1698
1699 #[profiling::function]
1700 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1701 Self::Node::new(
1705 graph.resources.bind_shared(self),
1706 #[cfg(feature = "checked")]
1707 graph.graph_id,
1708 )
1709 }
1710 }
1711
1712 impl<'a> Resource for &'a Arc<$name> {
1713 type Node = [<$name Node>];
1714
1715 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1716 Arc::clone(self).bind_graph(graph)
1719 }
1720 }
1721
1722 impl Resource for Lease<$name> {
1723 type Node = [<$name LeaseNode>];
1724
1725 #[profiling::function]
1726 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1727 Arc::new(self).bind_graph(graph)
1731 }
1732 }
1733
1734 impl Resource for Arc<Lease<$name>> {
1735 type Node = [<$name LeaseNode>];
1736
1737 #[profiling::function]
1738 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1739 Self::Node::new(
1744 graph.resources.bind_shared(self),
1745 #[cfg(feature = "checked")]
1746 graph.graph_id,
1747 )
1748 }
1749 }
1750
1751 impl<'a> Resource for &'a Arc<Lease<$name>> {
1752 type Node = [<$name LeaseNode>];
1753
1754 fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1755 Arc::clone(self).bind_graph(graph)
1759 }
1760 }
1761 }
1762 };
1763}
1764
1765resource!(AccelerationStructure);
1766resource!(Image);
1767resource!(Buffer);
1768
1769#[derive(Debug, Default)]
1770struct ResourceMap {
1771 addr_index: HashMap<usize, NodeIndex>,
1772 resources: Vec<AnyResource>,
1773}
1774
1775impl ResourceMap {
1776 pub(crate) fn from_resources(resources: Vec<AnyResource>) -> Self {
1777 Self {
1778 addr_index: HashMap::new(),
1779 resources,
1780 }
1781 }
1782
1783 fn bind(&mut self, resource: AnyResource) -> NodeIndex {
1784 let node_idx = self.resources.len();
1785 self.resources.push(resource);
1786
1787 node_idx
1788 }
1789
1790 fn bind_shared<T>(&mut self, resource: Arc<T>) -> NodeIndex
1791 where
1792 Arc<T>: Into<AnyResource>,
1793 {
1794 let addr = Arc::as_ptr(&resource) as usize;
1795
1796 *self.addr_index.entry(addr).or_insert_with(|| {
1797 let node_idx = self.resources.len();
1798 self.resources.push(resource.into());
1799
1800 node_idx
1801 })
1802 }
1803}
1804
1805impl Deref for ResourceMap {
1806 type Target = [AnyResource];
1807
1808 fn deref(&self) -> &Self::Target {
1809 &self.resources
1810 }
1811}
1812
1813impl DerefMut for ResourceMap {
1814 fn deref_mut(&mut self) -> &mut Self::Target {
1815 &mut self.resources
1816 }
1817}
1818
1819#[derive(Clone, Copy, Debug, PartialEq)]
1824pub enum StoreOp {
1825 DontCare,
1827
1828 Store,
1830}
1831
1832#[cfg(test)]
1833mod test {
1834 use std::sync::Arc;
1835
1836 use ash::vk;
1837
1838 use super::{AnyResource, Graph, Node, ResourceMap};
1839 use crate::driver::{
1840 DriverError,
1841 accel_struct::{AccelerationStructure, AccelerationStructureInfo},
1842 buffer::{Buffer, BufferInfo},
1843 device::{Device, DeviceInfo},
1844 image::{Image, ImageInfo},
1845 swapchain::SwapchainImage,
1846 };
1847 use crate::pool::{Pool, hash::HashPool};
1848
1849 mod integration {
1850 use super::*;
1851
1852 fn test_device() -> Result<Device, DriverError> {
1853 Device::create(DeviceInfo::default())
1854 }
1855
1856 mod resource_map {
1857 use super::*;
1858
1859 #[test]
1860 #[ignore = "requires Vulkan device"]
1861 fn bind_assigns_a_new_node_index_every_time() -> Result<(), DriverError> {
1862 let device = test_device()?;
1863 let buffer = Arc::new(Buffer::create(
1864 &device,
1865 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
1866 )?);
1867 let image = Arc::new(Image::create(
1868 &device,
1869 ImageInfo::image_2d(
1870 1,
1871 1,
1872 vk::Format::R8G8B8A8_UNORM,
1873 vk::ImageUsageFlags::SAMPLED,
1874 ),
1875 )?);
1876 let mut resources = ResourceMap::default();
1877
1878 assert_eq!(resources.bind(AnyResource::from(buffer)), 0);
1879 assert_eq!(resources.bind(AnyResource::from(image)), 1);
1880 assert_eq!(resources.len(), 2);
1881
1882 Ok(())
1883 }
1884
1885 #[test]
1886 #[ignore = "requires Vulkan device"]
1887 fn bind_shared_reuses_the_existing_node_index_for_the_same_address()
1888 -> Result<(), DriverError> {
1889 let device = test_device()?;
1890 let buffer = Arc::new(Buffer::create(
1891 &device,
1892 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
1893 )?);
1894 let mut resources = ResourceMap::default();
1895
1896 assert_eq!(resources.bind_shared(Arc::clone(&buffer)), 0);
1897 assert_eq!(resources.bind_shared(buffer), 0);
1898 assert_eq!(resources.len(), 1);
1899
1900 Ok(())
1901 }
1902
1903 #[test]
1904 #[ignore = "requires Vulkan device"]
1905 fn bind_shared_creates_distinct_node_indices_for_different_addresses()
1906 -> Result<(), DriverError> {
1907 let device = test_device()?;
1908 let buffer = Arc::new(Buffer::create(
1909 &device,
1910 BufferInfo::device_mem(4, vk::BufferUsageFlags::STORAGE_BUFFER),
1911 )?);
1912 let image = Arc::new(Image::create(
1913 &device,
1914 ImageInfo::image_2d(
1915 1,
1916 1,
1917 vk::Format::R8G8B8A8_UNORM,
1918 vk::ImageUsageFlags::SAMPLED,
1919 ),
1920 )?);
1921 let mut resources = ResourceMap::default();
1922
1923 assert_eq!(resources.bind_shared(buffer), 0);
1924 assert_eq!(resources.bind_shared(image), 1);
1925 assert_eq!(resources.len(), 2);
1926
1927 Ok(())
1928 }
1929
1930 #[test]
1931 #[ignore = "requires Vulkan device"]
1932 fn graph_bind_fuzzes_all_resource_paths() -> Result<(), DriverError> {
1933 #[derive(Clone, Copy)]
1934 enum ResourceKind {
1935 OwnedBuffer,
1936 SharedBuffer,
1937 OwnedBufferLease,
1938 SharedBufferLease,
1939 OwnedImage,
1940 SharedImage,
1941 OwnedImageLease,
1942 SharedImageLease,
1943 SwapchainImage,
1944 OwnedAccelerationStructure,
1945 SharedAccelerationStructure,
1946 OwnedAccelerationStructureLease,
1947 SharedAccelerationStructureLease,
1948 }
1949
1950 struct SharedNodes<T> {
1951 values: Vec<(Arc<T>, usize)>,
1952 }
1953
1954 impl<T> Default for SharedNodes<T> {
1955 fn default() -> Self {
1956 Self { values: Vec::new() }
1957 }
1958 }
1959
1960 impl<T> SharedNodes<T> {
1961 fn get(&self, idx: usize) -> Option<(Arc<T>, usize)> {
1962 self.values
1963 .get(idx)
1964 .map(|(resource, node_idx)| (Arc::clone(resource), *node_idx))
1965 }
1966
1967 fn push(&mut self, resource: Arc<T>, node_idx: usize) {
1968 self.values.push((resource, node_idx));
1969 }
1970
1971 fn len(&self) -> usize {
1972 self.values.len()
1973 }
1974 }
1975
1976 fn next_rand(state: &mut u64) -> u64 {
1977 *state ^= *state << 13;
1978 *state ^= *state >> 7;
1979 *state ^= *state << 17;
1980 *state
1981 }
1982
1983 let device = test_device()?;
1984 let mut pool = HashPool::new(&device);
1985 let mut graph = Graph::new();
1986
1987 let mut rand_state = 0x5eed_u64;
1988 let mut shared_buffers = SharedNodes::<Buffer>::default();
1989 let mut shared_buffer_leases = SharedNodes::<crate::pool::Lease<Buffer>>::default();
1990 let mut shared_images = SharedNodes::<Image>::default();
1991 let mut shared_image_leases = SharedNodes::<crate::pool::Lease<Image>>::default();
1992 let mut shared_accels = SharedNodes::<AccelerationStructure>::default();
1993 let mut shared_accel_leases =
1994 SharedNodes::<crate::pool::Lease<AccelerationStructure>>::default();
1995 let accel_supported = device.physical.vk_khr_acceleration_structure.is_some();
1996
1997 let mut resource_kinds = vec![
1998 ResourceKind::OwnedBuffer,
1999 ResourceKind::SharedBuffer,
2000 ResourceKind::OwnedBufferLease,
2001 ResourceKind::SharedBufferLease,
2002 ResourceKind::OwnedImage,
2003 ResourceKind::SharedImage,
2004 ResourceKind::OwnedImageLease,
2005 ResourceKind::SharedImageLease,
2006 ResourceKind::SwapchainImage,
2007 ];
2008
2009 if accel_supported {
2010 resource_kinds.push(ResourceKind::OwnedAccelerationStructure);
2011 resource_kinds.push(ResourceKind::SharedAccelerationStructure);
2012 resource_kinds.push(ResourceKind::OwnedAccelerationStructureLease);
2013 resource_kinds.push(ResourceKind::SharedAccelerationStructureLease);
2014 }
2015
2016 for step in 0..64 {
2017 let kind = resource_kinds
2018 [(next_rand(&mut rand_state) as usize) % resource_kinds.len()];
2019 let expect_new = match kind {
2020 ResourceKind::OwnedBuffer
2021 | ResourceKind::OwnedBufferLease
2022 | ResourceKind::OwnedImage
2023 | ResourceKind::OwnedImageLease
2024 | ResourceKind::SwapchainImage
2025 | ResourceKind::OwnedAccelerationStructure
2026 | ResourceKind::OwnedAccelerationStructureLease => true,
2027 ResourceKind::SharedBuffer => {
2028 shared_buffers.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2029 }
2030 ResourceKind::SharedBufferLease => {
2031 shared_buffer_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2032 }
2033 ResourceKind::SharedImage => {
2034 shared_images.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2035 }
2036 ResourceKind::SharedImageLease => {
2037 shared_image_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2038 }
2039 ResourceKind::SharedAccelerationStructure => {
2040 shared_accels.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2041 }
2042 ResourceKind::SharedAccelerationStructureLease => {
2043 shared_accel_leases.len() == 0 || next_rand(&mut rand_state) & 1 == 0
2044 }
2045 };
2046
2047 let expected_node_idx = graph.resources.len();
2048
2049 let node_idx = match kind {
2050 ResourceKind::OwnedBuffer => graph
2051 .bind_resource(Buffer::create(
2052 &device,
2053 BufferInfo::device_mem(
2054 16 + step,
2055 vk::BufferUsageFlags::STORAGE_BUFFER,
2056 ),
2057 )?)
2058 .index(),
2059 ResourceKind::SharedBuffer if expect_new => {
2060 let resource = Arc::new(Buffer::create(
2061 &device,
2062 BufferInfo::device_mem(
2063 16 + step,
2064 vk::BufferUsageFlags::STORAGE_BUFFER,
2065 ),
2066 )?);
2067 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2068 shared_buffers.push(resource, node_idx);
2069 node_idx
2070 }
2071 ResourceKind::SharedBuffer => {
2072 let reuse_idx =
2073 (next_rand(&mut rand_state) as usize) % shared_buffers.len();
2074 let (resource, node_idx) = shared_buffers.get(reuse_idx).unwrap();
2075 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2076 node_idx
2077 }
2078 ResourceKind::OwnedBufferLease => graph
2079 .bind_resource(pool.resource(BufferInfo::device_mem(
2080 32 + step,
2081 vk::BufferUsageFlags::STORAGE_BUFFER,
2082 ))?)
2083 .index(),
2084 ResourceKind::SharedBufferLease if expect_new => {
2085 let resource = Arc::new(pool.resource(BufferInfo::device_mem(
2086 32 + step,
2087 vk::BufferUsageFlags::STORAGE_BUFFER,
2088 ))?);
2089 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2090 shared_buffer_leases.push(resource, node_idx);
2091 node_idx
2092 }
2093 ResourceKind::SharedBufferLease => {
2094 let reuse_idx =
2095 (next_rand(&mut rand_state) as usize) % shared_buffer_leases.len();
2096 let (resource, node_idx) = shared_buffer_leases.get(reuse_idx).unwrap();
2097 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2098 node_idx
2099 }
2100 ResourceKind::OwnedImage => graph
2101 .bind_resource(Image::create(
2102 &device,
2103 ImageInfo::image_2d(
2104 1,
2105 1,
2106 vk::Format::R8G8B8A8_UNORM,
2107 vk::ImageUsageFlags::SAMPLED,
2108 ),
2109 )?)
2110 .index(),
2111 ResourceKind::SharedImage if expect_new => {
2112 let resource = Arc::new(Image::create(
2113 &device,
2114 ImageInfo::image_2d(
2115 1,
2116 1,
2117 vk::Format::R8G8B8A8_UNORM,
2118 vk::ImageUsageFlags::SAMPLED,
2119 ),
2120 )?);
2121 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2122 shared_images.push(resource, node_idx);
2123 node_idx
2124 }
2125 ResourceKind::SharedImage => {
2126 let reuse_idx =
2127 (next_rand(&mut rand_state) as usize) % shared_images.len();
2128 let (resource, node_idx) = shared_images.get(reuse_idx).unwrap();
2129 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2130 node_idx
2131 }
2132 ResourceKind::OwnedImageLease => graph
2133 .bind_resource(pool.resource(ImageInfo::image_2d(
2134 1,
2135 1,
2136 vk::Format::R8G8B8A8_UNORM,
2137 vk::ImageUsageFlags::SAMPLED,
2138 ))?)
2139 .index(),
2140 ResourceKind::SharedImageLease if expect_new => {
2141 let resource = Arc::new(pool.resource(ImageInfo::image_2d(
2142 1,
2143 1,
2144 vk::Format::R8G8B8A8_UNORM,
2145 vk::ImageUsageFlags::SAMPLED,
2146 ))?);
2147 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2148 shared_image_leases.push(resource, node_idx);
2149 node_idx
2150 }
2151 ResourceKind::SharedImageLease => {
2152 let reuse_idx =
2153 (next_rand(&mut rand_state) as usize) % shared_image_leases.len();
2154 let (resource, node_idx) = shared_image_leases.get(reuse_idx).unwrap();
2155 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2156 node_idx
2157 }
2158 ResourceKind::SwapchainImage => graph
2159 .bind_resource(SwapchainImage::from_raw(
2160 &device,
2161 vk::Image::null(),
2162 ImageInfo::image_2d(
2163 1,
2164 1,
2165 vk::Format::R8G8B8A8_UNORM,
2166 vk::ImageUsageFlags::COLOR_ATTACHMENT,
2167 ),
2168 step as u32,
2169 ))
2170 .index(),
2171 ResourceKind::OwnedAccelerationStructure => graph
2172 .bind_resource(AccelerationStructure::create(
2173 &device,
2174 AccelerationStructureInfo::blas(256 + step),
2175 )?)
2176 .index(),
2177 ResourceKind::SharedAccelerationStructure if expect_new => {
2178 let resource = Arc::new(AccelerationStructure::create(
2179 &device,
2180 AccelerationStructureInfo::blas(256 + step),
2181 )?);
2182 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2183 shared_accels.push(resource, node_idx);
2184 node_idx
2185 }
2186 ResourceKind::SharedAccelerationStructure => {
2187 let reuse_idx =
2188 (next_rand(&mut rand_state) as usize) % shared_accels.len();
2189 let (resource, node_idx) = shared_accels.get(reuse_idx).unwrap();
2190 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2191 node_idx
2192 }
2193 ResourceKind::OwnedAccelerationStructureLease => graph
2194 .bind_resource(
2195 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2196 )
2197 .index(),
2198 ResourceKind::SharedAccelerationStructureLease if expect_new => {
2199 let resource = Arc::new(
2200 pool.resource(AccelerationStructureInfo::blas(512 + step))?,
2201 );
2202 let node_idx = graph.bind_resource(Arc::clone(&resource)).index();
2203 shared_accel_leases.push(resource, node_idx);
2204 node_idx
2205 }
2206 ResourceKind::SharedAccelerationStructureLease => {
2207 let reuse_idx =
2208 (next_rand(&mut rand_state) as usize) % shared_accel_leases.len();
2209 let (resource, node_idx) = shared_accel_leases.get(reuse_idx).unwrap();
2210 assert_eq!(graph.bind_resource(resource).index(), node_idx);
2211 node_idx
2212 }
2213 };
2214
2215 if expect_new {
2216 assert_eq!(node_idx, expected_node_idx);
2217 assert_eq!(graph.resources.len(), expected_node_idx + 1);
2218 } else {
2219 assert!(node_idx < expected_node_idx);
2220 assert_eq!(graph.resources.len(), expected_node_idx);
2221 }
2222 }
2223
2224 Ok(())
2225 }
2226 }
2227 }
2228}