1use crate::private::NodeSealed;
58use {
59 crate::{
60 AnyResource, Graph, Node, Resource, ResourceMap,
61 cmd::{
62 AttachmentIndex, ClearColorValue, Command, CommandRef, ComputeCommandRef,
63 GraphicsCommandRef, LoadOp, PipelineCommand, RayTracingCommandRef, StoreOp,
64 Subresource, SubresourceRange,
65 },
66 driver::{
67 DriverError,
68 accel_struct::{
69 AccelerationStructure, AccelerationStructureInfo, AccelerationStructureInfoBuilder,
70 },
71 buffer::{Buffer, BufferInfo, BufferInfoBuilder},
72 compute::ComputePipeline,
73 graphics::{DepthStencilInfo, GraphicsPipeline},
74 image::{Image, ImageInfo, ImageInfoBuilder, ImageViewInfo},
75 ray_tracing::RayTracingPipeline,
76 },
77 node::{
78 AccelerationStructureLeaseNode, AccelerationStructureNode,
79 AnyAccelerationStructureNode, AnyBufferNode, AnyImageNode, BufferLeaseNode, BufferNode,
80 ImageLeaseNode, ImageNode, SwapchainImageNode,
81 },
82 pool::SubmissionPool,
83 submission::Submission,
84 },
85 ash::vk,
86 std::{
87 collections::HashMap,
88 marker::PhantomData,
89 ops::Range,
90 sync::{Arc, Mutex},
91 },
92};
93
94#[cfg(feature = "checked")]
95use crate::GraphId;
96
97use std::sync::atomic::{AtomicU64, Ordering};
98
99fn next_stream_scope_id() -> u64 {
100 static NEXT_ID: AtomicU64 = AtomicU64::new(1);
101
102 NEXT_ID.fetch_add(1, Ordering::Relaxed)
103}
104
105#[cfg(feature = "checked")]
106#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
107pub(crate) struct CommandStreamId(u64);
108
109#[cfg(feature = "checked")]
110impl CommandStreamId {
111 fn next() -> Self {
112 Self(next_stream_scope_id())
113 }
114}
115
116#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
142pub struct StreamArg<T> {
143 pub(crate) arg_index: usize,
144 pub(crate) index: usize,
145
146 #[cfg(feature = "checked")]
147 pub(crate) stream_id: CommandStreamId,
148
149 #[cfg(feature = "checked")]
150 pub(crate) graph_id: GraphId,
151
152 __: PhantomData<fn() -> T>,
153}
154
155impl<T> Clone for StreamArg<T> {
156 fn clone(&self) -> Self {
157 *self
158 }
159}
160
161impl<T> Copy for StreamArg<T> {}
162
163impl<T> StreamArg<T> {
164 pub(crate) fn new(
165 arg_index: usize,
166 index: usize,
167 #[cfg(feature = "checked")] stream_id: CommandStreamId,
168 #[cfg(feature = "checked")] graph_id: GraphId,
169 ) -> Self {
170 Self {
171 arg_index,
172 index,
173 #[cfg(feature = "checked")]
174 stream_id,
175 #[cfg(feature = "checked")]
176 graph_id,
177 __: PhantomData,
178 }
179 }
180}
181
182impl NodeSealed for StreamArg<AccelerationStructure> {
183 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource {
184 resources[self.index].expect_accel_struct()
185 }
186
187 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource {
188 resources[index].expect_accel_struct()
189 }
190
191 #[cfg(feature = "checked")]
192 fn assert_owner(&self, _graph_id: GraphId) {
193 #[cfg(feature = "checked")]
194 assert!(
195 self.graph_id == _graph_id,
196 "node belongs to a different graph"
197 );
198 }
199}
200
201impl Node for StreamArg<AccelerationStructure> {
202 type Resource = AccelerationStructure;
203 type SyncInfo = crate::driver::accel_struct::AccelerationStructureSyncInfo;
204
205 fn index(&self) -> usize {
206 self.index
207 }
208}
209
210impl NodeSealed for StreamArg<Buffer> {
211 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource {
212 resources[self.index].expect_buffer()
213 }
214
215 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource {
216 resources[index].expect_buffer()
217 }
218
219 #[cfg(feature = "checked")]
220 fn assert_owner(&self, _graph_id: GraphId) {
221 #[cfg(feature = "checked")]
222 assert!(
223 self.graph_id == _graph_id,
224 "node belongs to a different graph"
225 );
226 }
227}
228
229impl Node for StreamArg<Buffer> {
230 type Resource = Buffer;
231 type SyncInfo = crate::driver::buffer::BufferSyncInfo;
232
233 fn index(&self) -> usize {
234 self.index
235 }
236}
237
238impl NodeSealed for StreamArg<Image> {
239 fn borrow(self, resources: &[AnyResource]) -> &<Self as Node>::Resource {
240 resources[self.index].expect_image()
241 }
242
243 fn borrow_at(self, resources: &[AnyResource], index: usize) -> &<Self as Node>::Resource {
244 resources[index].expect_image()
245 }
246
247 #[cfg(feature = "checked")]
248 fn assert_owner(&self, _graph_id: GraphId) {
249 #[cfg(feature = "checked")]
250 assert!(
251 self.graph_id == _graph_id,
252 "node belongs to a different graph"
253 );
254 }
255}
256
257impl Node for StreamArg<Image> {
258 type Resource = Image;
259 type SyncInfo = crate::driver::image::ImageSyncInfo;
260
261 fn index(&self) -> usize {
262 self.index
263 }
264}
265
266pub type AccelerationStructureArg = StreamArg<AccelerationStructure>;
278
279pub type BufferArg = StreamArg<Buffer>;
294
295pub type ImageArg = StreamArg<Image>;
312
313#[derive(Clone, Copy, Debug)]
314pub(crate) enum StreamArgData {
315 AccelerationStructure(AccelerationStructureInfo),
316 Buffer(BufferInfo),
317 Image(ImageInfo),
318}
319
320#[derive(Debug)]
321pub(crate) struct CommandStreamInner {
322 pub(crate) arg_nodes: Box<[usize]>,
323 pub(crate) args: Box<[StreamArgData]>,
324 pub(crate) prepared: bool,
325 pub(crate) submission: Mutex<Submission>,
326
327 #[cfg(feature = "checked")]
328 pub(crate) stream_id: CommandStreamId,
329
330 #[cfg(feature = "checked")]
331 pub(crate) graph_id: GraphId,
332}
333
334#[derive(Clone, Debug)]
356pub struct CommandStream<A = ()> {
357 pub args: A,
359 pub(crate) inner: Arc<CommandStreamInner>,
360}
361
362#[derive(Debug)]
381pub struct CommandStreamDraft<A = ()> {
382 pub args: A,
384 inner: CommandStreamInner,
385}
386
387pub struct CommandStreamMut {
407 pub(crate) arg_nodes: Vec<usize>,
408 pub(crate) args: Vec<StreamArgData>,
409 pub(crate) graph: Graph,
410 #[cfg(feature = "checked")]
411 pub(crate) stream_id: CommandStreamId,
412}
413
414pub struct StreamCommand<'a> {
429 inner: Command<'a>,
430}
431
432pub struct StreamPipelineCommand<'a, T> {
449 inner: PipelineCommand<'a, T>,
450}
451
452#[doc(hidden)]
454pub trait StreamPipeline<'a>: stream_private::StreamPipelineSealed {
455 type Command;
457
458 fn bind_stream_cmd(self, cmd: StreamCommand<'a>) -> Self::Command;
460}
461
462macro_rules! stream_pipeline {
463 ($pipeline:ty) => {
464 impl<'a> StreamPipeline<'a> for $pipeline {
465 type Command = StreamPipelineCommand<'a, $pipeline>;
466
467 fn bind_stream_cmd(self, cmd: StreamCommand<'a>) -> Self::Command {
468 StreamPipelineCommand {
469 inner: cmd.inner.bind_pipeline(self),
470 }
471 }
472 }
473
474 impl stream_private::StreamPipelineSealed for $pipeline {}
475
476 impl<'a> StreamPipeline<'a> for &'a $pipeline {
477 type Command = StreamPipelineCommand<'a, $pipeline>;
478
479 fn bind_stream_cmd(self, cmd: StreamCommand<'a>) -> Self::Command {
480 StreamPipelineCommand {
481 inner: cmd.inner.bind_pipeline(self),
482 }
483 }
484 }
485
486 impl<'a> stream_private::StreamPipelineSealed for &'a $pipeline {}
487 };
488}
489
490stream_pipeline!(ComputePipeline);
491stream_pipeline!(GraphicsPipeline);
492stream_pipeline!(RayTracingPipeline);
493
494#[allow(private_bounds)]
495impl<'a> StreamCommand<'a> {
496 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
498 where
499 R: Resource,
500 {
501 self.inner.bind_resource(resource)
502 }
503
504 pub fn bind_pipeline<P>(self, pipeline: P) -> P::Command
506 where
507 P: StreamPipeline<'a>,
508 {
509 pipeline.bind_stream_cmd(self)
510 }
511
512 pub fn debug_name(mut self, name: impl Into<String>) -> Self {
514 self.inner.set_debug_name(name);
515 self
516 }
517
518 pub fn record_cmd(
523 mut self,
524 func: impl for<'r> Fn(CommandRef<'r>) + Send + Sync + 'static,
525 ) -> Self {
526 self.record_cmd_mut(func);
527 self
528 }
529
530 pub fn record_cmd_mut(
535 &mut self,
536 func: impl for<'r> Fn(CommandRef<'r>) + Send + Sync + 'static,
537 ) {
538 self.inner.record_stream_mut(func);
539 }
540
541 pub fn resource_access<N>(mut self, resource_node: N, access: vk_sync::AccessType) -> Self
543 where
544 N: Node + Subresource,
545 SubresourceRange: From<N::Range>,
546 {
547 self.inner.set_resource_access(resource_node, access);
548 self
549 }
550
551 pub fn set_resource_access<N>(&mut self, resource_node: N, access: vk_sync::AccessType)
553 where
554 N: Node + Subresource,
555 SubresourceRange: From<N::Range>,
556 {
557 self.inner.set_resource_access(resource_node, access);
558 }
559}
560
561#[allow(private_bounds)]
562impl<'a, T> StreamPipelineCommand<'a, T> {
563 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
565 where
566 R: Resource,
567 {
568 self.inner.bind_resource(resource)
569 }
570
571 pub fn resource_access<N>(mut self, resource_node: N, access: vk_sync::AccessType) -> Self
573 where
574 N: Node + Subresource,
575 SubresourceRange: From<N::Range>,
576 {
577 self.inner.set_resource_access(resource_node, access);
578 self
579 }
580
581 pub fn set_resource_access<N>(
583 &mut self,
584 resource_node: N,
585 access: vk_sync::AccessType,
586 ) -> &mut Self
587 where
588 N: Node + Subresource,
589 SubresourceRange: From<N::Range>,
590 {
591 self.inner.set_resource_access(resource_node, access);
592 self
593 }
594}
595
596impl StreamPipelineCommand<'_, ComputePipeline> {
597 pub fn record_cmd(
602 mut self,
603 func: impl for<'r> Fn(ComputeCommandRef<'r>) + Send + Sync + 'static,
604 ) -> Self {
605 self.record_cmd_mut(func);
606 self
607 }
608
609 pub fn record_cmd_mut(
614 &mut self,
615 func: impl for<'r> Fn(ComputeCommandRef<'r>) + Send + Sync + 'static,
616 ) {
617 self.inner.record_stream_mut(func);
618 }
619}
620
621impl StreamPipelineCommand<'_, GraphicsPipeline> {
622 pub fn depth_stencil(mut self, depth_stencil: impl Into<DepthStencilInfo>) -> Self {
624 self.inner.set_depth_stencil(depth_stencil);
625 self
626 }
627
628 pub fn color_attachment_image(
630 mut self,
631 color_attachment: AttachmentIndex,
632 image: impl Into<AnyImageNode>,
633 load: LoadOp<ClearColorValue>,
634 store: StoreOp,
635 ) -> Self {
636 self.inner
637 .set_color_attachment_image(color_attachment, image, load, store);
638 self
639 }
640
641 pub fn color_attachment_image_view(
643 mut self,
644 color_attachment: AttachmentIndex,
645 image: impl Into<AnyImageNode>,
646 image_view_info: impl Into<ImageViewInfo>,
647 load: LoadOp<ClearColorValue>,
648 store: StoreOp,
649 ) -> Self {
650 self.inner.set_color_attachment_image_view(
651 color_attachment,
652 image,
653 image_view_info,
654 load,
655 store,
656 );
657 self
658 }
659
660 pub fn depth_stencil_attachment_image(
662 mut self,
663 image: impl Into<AnyImageNode>,
664 load: LoadOp<vk::ClearDepthStencilValue>,
665 store: StoreOp,
666 ) -> Self {
667 self.inner
668 .set_depth_stencil_attachment_image(image, load, store);
669 self
670 }
671
672 pub fn record_cmd(
677 mut self,
678 func: impl for<'r> Fn(GraphicsCommandRef<'r>) + Send + Sync + 'static,
679 ) -> Self {
680 self.record_cmd_mut(func);
681 self
682 }
683
684 pub fn record_cmd_mut(
689 &mut self,
690 func: impl for<'r> Fn(GraphicsCommandRef<'r>) + Send + Sync + 'static,
691 ) {
692 self.inner.record_stream_mut(func);
693 }
694}
695
696impl StreamPipelineCommand<'_, RayTracingPipeline> {
697 pub fn record_cmd(
702 mut self,
703 func: impl for<'r> Fn(RayTracingCommandRef<'r>) + Send + Sync + 'static,
704 ) -> Self {
705 self.record_cmd_mut(func);
706 self
707 }
708
709 pub fn record_cmd_mut(
714 &mut self,
715 func: impl for<'r> Fn(RayTracingCommandRef<'r>) + Send + Sync + 'static,
716 ) {
717 self.inner.record_stream_mut(func);
718 }
719}
720
721impl CommandStreamMut {
722 pub fn arg<I>(&mut self, info: I) -> I::Arg
724 where
725 I: StreamArgInfo,
726 {
727 info.bind_stream_arg(self)
728 }
729
730 pub fn begin_cmd(&mut self) -> StreamCommand<'_> {
732 StreamCommand {
733 inner: self.graph.begin_cmd(),
734 }
735 }
736
737 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
739 where
740 R: Resource,
741 {
742 self.graph.bind_resource(resource)
743 }
744
745 pub fn resource<N>(&self, resource_node: N) -> &N::Resource
747 where
748 N: StreamResourceNode,
749 {
750 self.graph.resource(resource_node)
751 }
752
753 pub fn blit_image(
755 &mut self,
756 src: impl Into<AnyImageNode>,
757 dst: impl Into<AnyImageNode>,
758 filter: vk::Filter,
759 ) -> &mut Self {
760 self.graph.blit_image(src, dst, filter);
761 self
762 }
763
764 #[doc(hidden)]
766 #[deprecated(note = "use Command::blit_image for explicit regions")]
767 pub fn blit_image_region(
768 &mut self,
769 src: impl Into<AnyImageNode>,
770 dst: impl Into<AnyImageNode>,
771 filter: vk::Filter,
772 regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
773 ) -> &mut Self {
774 self.graph
775 .begin_cmd()
776 .debug_name("blit image")
777 .blit_image(src, dst, filter, regions)
778 .end_cmd();
779 self
780 }
781
782 pub fn clear_color_image(
784 &mut self,
785 image: impl Into<AnyImageNode>,
786 color: impl Into<ClearColorValue>,
787 ) -> &mut Self {
788 self.graph.clear_color_image(image, color);
789 self
790 }
791
792 pub fn clear_depth_stencil_image(
794 &mut self,
795 image: impl Into<AnyImageNode>,
796 depth: f32,
797 stencil: u32,
798 ) -> &mut Self {
799 self.graph.clear_depth_stencil_image(image, depth, stencil);
800 self
801 }
802
803 pub fn copy_buffer(
805 &mut self,
806 src: impl Into<AnyBufferNode>,
807 dst: impl Into<AnyBufferNode>,
808 ) -> &mut Self {
809 self.graph.copy_buffer(src, dst);
810 self
811 }
812
813 #[doc(hidden)]
815 #[deprecated(note = "use Command::copy_buffer for explicit regions")]
816 pub fn copy_buffer_region(
817 &mut self,
818 src: impl Into<AnyBufferNode>,
819 dst: impl Into<AnyBufferNode>,
820 regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
821 ) -> &mut Self {
822 self.graph
823 .begin_cmd()
824 .debug_name("copy buffer")
825 .copy_buffer(src, dst, regions)
826 .end_cmd();
827 self
828 }
829
830 pub fn copy_buffer_to_image(
832 &mut self,
833 src: impl Into<AnyBufferNode>,
834 dst: impl Into<AnyImageNode>,
835 ) -> &mut Self {
836 self.graph.copy_buffer_to_image(src, dst);
837 self
838 }
839
840 #[doc(hidden)]
842 #[deprecated(note = "use Command::copy_buffer_to_image for explicit regions")]
843 pub fn copy_buffer_to_image_region(
844 &mut self,
845 src: impl Into<AnyBufferNode>,
846 dst: impl Into<AnyImageNode>,
847 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
848 ) -> &mut Self {
849 self.graph
850 .begin_cmd()
851 .debug_name("copy buffer to image")
852 .copy_buffer_to_image(src, dst, regions)
853 .end_cmd();
854 self
855 }
856
857 pub fn copy_image(
859 &mut self,
860 src: impl Into<AnyImageNode>,
861 dst: impl Into<AnyImageNode>,
862 ) -> &mut Self {
863 self.graph.copy_image(src, dst);
864 self
865 }
866
867 #[doc(hidden)]
869 #[deprecated(note = "use Command::copy_image for explicit regions")]
870 pub fn copy_image_region(
871 &mut self,
872 src: impl Into<AnyImageNode>,
873 dst: impl Into<AnyImageNode>,
874 regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
875 ) -> &mut Self {
876 self.graph
877 .begin_cmd()
878 .debug_name("copy image")
879 .copy_image(src, dst, regions)
880 .end_cmd();
881 self
882 }
883
884 pub fn copy_image_to_buffer(
886 &mut self,
887 src: impl Into<AnyImageNode>,
888 dst: impl Into<AnyBufferNode>,
889 ) -> &mut Self {
890 self.graph.copy_image_to_buffer(src, dst);
891 self
892 }
893
894 #[doc(hidden)]
896 #[deprecated(note = "use Command::copy_image_to_buffer for explicit regions")]
897 pub fn copy_image_to_buffer_region(
898 &mut self,
899 src: impl Into<AnyImageNode>,
900 dst: impl Into<AnyBufferNode>,
901 regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
902 ) -> &mut Self {
903 self.graph
904 .begin_cmd()
905 .debug_name("copy image to buffer")
906 .copy_image_to_buffer(src, dst, regions)
907 .end_cmd();
908 self
909 }
910
911 pub fn fill_buffer(
913 &mut self,
914 buffer: impl Into<AnyBufferNode>,
915 region: Range<vk::DeviceSize>,
916 data: u32,
917 ) -> &mut Self {
918 self.graph.fill_buffer(buffer, region, data);
919 self
920 }
921
922 pub fn update_buffer(
924 &mut self,
925 buffer: impl Into<AnyBufferNode>,
926 offset: vk::DeviceSize,
927 data: impl AsRef<[u8]> + 'static + Send,
928 ) -> &mut Self {
929 self.graph.update_buffer(buffer, offset, data);
930 self
931 }
932
933 fn push_arg(&mut self, data: StreamArgData) -> usize {
934 let index = self.args.len();
935 self.args.push(data);
936 index
937 }
938
939 fn bind_arg_resource(&mut self, data: StreamArgData) -> usize {
940 let resource = match data {
941 StreamArgData::AccelerationStructure(info) => {
942 AnyResource::AccelerationStructureArg(info)
943 }
944 StreamArgData::Buffer(info) => AnyResource::BufferArg(info),
945 StreamArgData::Image(info) => AnyResource::ImageArg(info),
946 };
947
948 self.graph.bind_stream_arg_resource(resource)
949 }
950}
951
952impl CommandStream<()> {
953 pub fn finalize<A>(build: impl FnOnce(&mut CommandStreamMut) -> A) -> CommandStreamDraft<A> {
958 let mut stream = CommandStreamMut {
959 arg_nodes: Vec::new(),
960 args: Vec::new(),
961 graph: Graph::new(),
962 #[cfg(feature = "checked")]
963 stream_id: CommandStreamId::next(),
964 };
965 let args = build(&mut stream);
966
967 #[cfg(feature = "checked")]
968 let graph_id = stream.graph.graph_id();
969
970 let submission = stream.graph.finalize();
971 submission.assert_reusable_commands();
972
973 CommandStreamDraft {
974 args,
975 inner: CommandStreamInner {
976 arg_nodes: stream.arg_nodes.into_boxed_slice(),
977 args: stream.args.into_boxed_slice(),
978 prepared: false,
979 submission: Mutex::new(submission),
980
981 #[cfg(feature = "checked")]
982 stream_id: stream.stream_id,
983
984 #[cfg(feature = "checked")]
985 graph_id,
986 },
987 }
988 }
989
990 pub fn prepare<P, A>(
995 pool: &mut P,
996 build: impl FnOnce(&mut CommandStreamMut) -> A,
997 ) -> Result<CommandStream<A>, DriverError>
998 where
999 P: SubmissionPool,
1000 {
1001 Self::finalize(build).prepare(pool)
1002 }
1003}
1004
1005impl<A> CommandStreamDraft<A> {
1006 pub fn into_stream(self) -> CommandStream<A> {
1011 CommandStream {
1012 args: self.args,
1013 inner: Arc::new(self.inner),
1014 }
1015 }
1016
1017 pub fn prepare<P>(mut self, pool: &mut P) -> Result<CommandStream<A>, DriverError>
1022 where
1023 P: SubmissionPool,
1024 {
1025 self.inner
1026 .submission
1027 .get_mut()
1028 .expect("poisoned command stream submission")
1029 .prepare_command_stream(pool)?;
1030 self.inner.prepared = true;
1031
1032 Ok(self.into_stream())
1033 }
1034}
1035
1036pub struct CommandStreamRun<'a, A> {
1062 pub(crate) bindings: Vec<Option<usize>>,
1063 pub(crate) graph: &'a mut Graph,
1064 pub(crate) stream: &'a CommandStream<A>,
1065}
1066
1067impl<'a, A> CommandStreamRun<'a, A> {
1068 pub fn with_arg<T, N>(mut self, arg: StreamArg<T>, node: N) -> Self
1077 where
1078 N: StreamArgBindable<T>,
1079 {
1080 #[cfg(feature = "checked")]
1081 assert!(
1082 arg.stream_id == self.stream.inner.stream_id,
1083 "argument belongs to a different command stream"
1084 );
1085 node.assert_parent_node();
1086 self.graph.assert_node_owner(&node);
1087 let node_idx = node.index();
1088 assert!(
1089 self.bindings
1090 .iter()
1091 .enumerate()
1092 .all(|(arg_idx, binding)| arg_idx == arg.arg_index || *binding != Some(node_idx)),
1093 "distinct command stream arguments cannot bind to the same parent graph node"
1094 );
1095 self.bindings[arg.arg_index] = Some(node_idx);
1096 self
1097 }
1098
1099 pub fn finish(self) -> &'a mut Graph {
1101 #[cfg(feature = "checked")]
1102 assert!(
1103 self.bindings.iter().all(Option::is_some),
1104 "missing command stream argument"
1105 );
1106
1107 self.graph
1108 .append_command_stream(self.stream, &self.bindings);
1109 self.graph
1110 }
1111}
1112
1113impl Graph {
1114 pub fn insert_cmd_stream<'a, A>(
1119 &'a mut self,
1120 stream: &'a CommandStream<A>,
1121 ) -> CommandStreamRun<'a, A> {
1122 CommandStreamRun {
1123 bindings: vec![None; stream.inner.args.len()],
1124 graph: self,
1125 stream,
1126 }
1127 }
1128}
1129
1130impl Graph {
1131 pub(crate) fn append_command_stream<A>(
1132 &mut self,
1133 stream: &CommandStream<A>,
1134 bindings: &[Option<usize>],
1135 ) {
1136 if stream.inner.prepared {
1137 self.append_prepared_command_stream(stream, bindings);
1138 } else {
1139 self.append_unprepared_command_stream(stream, bindings);
1140 }
1141 }
1142
1143 fn append_unprepared_command_stream<A>(
1144 &mut self,
1145 stream: &CommandStream<A>,
1146 bindings: &[Option<usize>],
1147 ) {
1148 let submission = stream
1149 .inner
1150 .submission
1151 .lock()
1152 .expect("poisoned command stream submission");
1153 let stream_graph = submission.graph();
1154 let mut arg_by_node = HashMap::new();
1155
1156 for (arg_idx, &node_idx) in stream.inner.arg_nodes.iter().enumerate() {
1157 arg_by_node.insert(node_idx, arg_idx);
1158 }
1159
1160 let mut node_map = Vec::with_capacity(stream_graph.resources.len());
1161 for (node_idx, resource) in stream_graph.resources.iter().enumerate() {
1162 if let Some(&arg_idx) = arg_by_node.get(&node_idx) {
1163 node_map.push(bindings[arg_idx].expect("missing command stream argument"));
1164 } else {
1165 node_map.push(self.resources.bind(resource.clone()));
1166 }
1167 }
1168
1169 for cmd in &stream_graph.cmds {
1170 let mut cmd = cmd.clone();
1171 cmd.remap_nodes(&node_map);
1172
1173 #[cfg(feature = "checked")]
1174 for exec in &mut cmd.execs {
1175 exec.stream_graph_id = Some(stream.inner.graph_id);
1176 }
1177
1178 self.cmds.push(cmd);
1179 }
1180 }
1181
1182 fn append_prepared_command_stream<A>(
1183 &mut self,
1184 stream: &CommandStream<A>,
1185 bindings: &[Option<usize>],
1186 ) {
1187 let stream_scope_id = next_stream_scope_id();
1188 let submission = stream
1189 .inner
1190 .submission
1191 .lock()
1192 .expect("poisoned command stream submission");
1193 let stream_graph = submission.graph();
1194 let mut arg_by_node = HashMap::new();
1195
1196 for (arg_idx, &node_idx) in stream.inner.arg_nodes.iter().enumerate() {
1197 arg_by_node.insert(node_idx, arg_idx);
1198 }
1199
1200 let mut cmd = self.begin_cmd().debug_name("command stream");
1201 cmd.set_stream_scope_id(stream_scope_id);
1202
1203 for stream_cmd in &stream_graph.cmds {
1204 for (node_idx, accesses) in stream_cmd
1205 .execs
1206 .iter()
1207 .flat_map(|exec| exec.accesses.iter())
1208 {
1209 let Some(&arg_idx) = arg_by_node.get(&node_idx) else {
1210 continue;
1211 };
1212 let parent_node_idx = bindings[arg_idx].expect("missing command stream argument");
1213
1214 for access in accesses {
1215 cmd.push_subresource_access_index(
1216 parent_node_idx,
1217 access.subresource,
1218 access.access,
1219 );
1220 }
1221 }
1222 }
1223
1224 drop(submission);
1225
1226 let stream = Arc::clone(&stream.inner);
1227 let bindings = bindings.to_vec();
1228 cmd.record_stream(move |cmd| {
1229 let submission = stream
1230 .submission
1231 .lock()
1232 .expect("poisoned command stream submission");
1233 let stream_graph = submission.graph();
1234 let mut arg_by_node = HashMap::new();
1235
1236 for (arg_idx, &node_idx) in stream.arg_nodes.iter().enumerate() {
1237 arg_by_node.insert(node_idx, arg_idx);
1238 }
1239
1240 let resources = stream_graph
1241 .resources
1242 .iter()
1243 .enumerate()
1244 .map(|(node_idx, resource)| {
1245 if let Some(&arg_idx) = arg_by_node.get(&node_idx) {
1246 cmd.clone_resource_at(
1247 bindings[arg_idx].expect("missing command stream argument"),
1248 )
1249 } else {
1250 resource.clone()
1251 }
1252 })
1253 .collect();
1254 drop(submission);
1255
1256 stream
1257 .submission
1258 .lock()
1259 .expect("poisoned command stream submission")
1260 .record_prepared_command_stream(&cmd, ResourceMap::from_resources(resources))
1261 .expect("unable to record command stream");
1262 });
1263 }
1264}
1265
1266#[allow(private_bounds)]
1268#[doc(hidden)]
1269pub trait StreamArgInfo: stream_private::StreamArgInfoSealed {
1270 type Arg;
1272
1273 #[doc(hidden)]
1274 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg;
1275}
1276
1277#[allow(private_bounds)]
1279#[doc(hidden)]
1280pub trait StreamArgBindable<T>: stream_private::StreamArgBindableSealed<T> + Node {
1281 #[doc(hidden)]
1282 fn assert_parent_node(&self);
1283}
1284
1285#[allow(private_bounds)]
1287#[doc(hidden)]
1288pub trait StreamResourceNode: stream_private::StreamResourceNodeSealed + Node {}
1289
1290mod stream_private {
1291 pub trait StreamArgInfoSealed {}
1292
1293 pub trait StreamArgBindableSealed<T> {}
1294
1295 pub trait StreamResourceNodeSealed {}
1296
1297 pub trait StreamPipelineSealed {}
1298}
1299
1300macro_rules! stream_arg_info {
1301 ($info:ty, $builder:ty, $variant:ident, $arg:ty) => {
1302 impl stream_private::StreamArgInfoSealed for $info {}
1303
1304 impl StreamArgInfo for $info {
1305 type Arg = $arg;
1306
1307 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg {
1308 let data = StreamArgData::$variant(self);
1309 let arg_index = stream.push_arg(data);
1310 let node_index = stream.bind_arg_resource(data);
1311 stream.arg_nodes.push(node_index);
1312 StreamArg::new(
1313 arg_index,
1314 node_index,
1315 #[cfg(feature = "checked")]
1316 stream.stream_id,
1317 #[cfg(feature = "checked")]
1318 stream.graph.graph_id(),
1319 )
1320 }
1321 }
1322
1323 impl stream_private::StreamArgInfoSealed for $builder {}
1324
1325 impl StreamArgInfo for $builder {
1326 type Arg = $arg;
1327
1328 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg {
1329 self.build().bind_stream_arg(stream)
1330 }
1331 }
1332 };
1333}
1334
1335stream_arg_info!(
1336 AccelerationStructureInfo,
1337 AccelerationStructureInfoBuilder,
1338 AccelerationStructure,
1339 AccelerationStructureArg
1340);
1341stream_arg_info!(BufferInfo, BufferInfoBuilder, Buffer, BufferArg);
1342stream_arg_info!(ImageInfo, ImageInfoBuilder, Image, ImageArg);
1343
1344macro_rules! stream_arg_bindable {
1345 ($resource:ty => $($node:ty),+ $(,)?) => {
1346 $(
1347 impl stream_private::StreamArgBindableSealed<$resource> for $node {}
1348
1349 impl StreamArgBindable<$resource> for $node {
1350 fn assert_parent_node(&self) {}
1351 }
1352 )+
1353 };
1354}
1355
1356stream_arg_bindable!(
1357 AccelerationStructure => AccelerationStructureNode,
1358 AccelerationStructureLeaseNode,
1359);
1360stream_arg_bindable!(Buffer => BufferNode, BufferLeaseNode);
1361stream_arg_bindable!(Image => ImageNode, ImageLeaseNode, SwapchainImageNode);
1362
1363impl stream_private::StreamArgBindableSealed<AccelerationStructure>
1364 for AnyAccelerationStructureNode
1365{
1366}
1367
1368impl StreamArgBindable<AccelerationStructure> for AnyAccelerationStructureNode {
1369 fn assert_parent_node(&self) {
1370 assert!(
1371 !matches!(self, Self::Arg(_)),
1372 "stream argument cannot be supplied as a parent graph node"
1373 );
1374 }
1375}
1376
1377impl stream_private::StreamArgBindableSealed<Buffer> for AnyBufferNode {}
1378
1379impl StreamArgBindable<Buffer> for AnyBufferNode {
1380 fn assert_parent_node(&self) {
1381 assert!(
1382 !matches!(self, Self::Arg(_)),
1383 "stream argument cannot be supplied as a parent graph node"
1384 );
1385 }
1386}
1387
1388impl stream_private::StreamArgBindableSealed<Image> for AnyImageNode {}
1389
1390impl StreamArgBindable<Image> for AnyImageNode {
1391 fn assert_parent_node(&self) {
1392 assert!(
1393 !matches!(self, Self::Arg(_)),
1394 "stream argument cannot be supplied as a parent graph node"
1395 );
1396 }
1397}
1398
1399macro_rules! stream_resource_node {
1400 ($($node:ty),+ $(,)?) => {
1401 $(
1402 impl stream_private::StreamResourceNodeSealed for $node {}
1403 impl StreamResourceNode for $node {}
1404 )+
1405 };
1406}
1407
1408stream_resource_node!(
1409 AccelerationStructureNode,
1410 AccelerationStructureLeaseNode,
1411 BufferNode,
1412 BufferLeaseNode,
1413 ImageNode,
1414 ImageLeaseNode,
1415 SwapchainImageNode,
1416);
1417
1418#[cfg(test)]
1419mod test {
1420 use super::*;
1421 use crate::{
1422 driver::{
1423 buffer::BufferInfo,
1424 descriptor_set::{DescriptorPool, DescriptorPoolInfo},
1425 render_pass::{RenderPass, RenderPassInfo},
1426 },
1427 pool::Pool,
1428 };
1429
1430 struct NoopPool;
1431
1432 impl Pool<DescriptorPoolInfo, DescriptorPool> for NoopPool {
1433 fn resource(
1434 &mut self,
1435 _: DescriptorPoolInfo,
1436 ) -> Result<crate::pool::Lease<DescriptorPool>, DriverError> {
1437 unreachable!()
1438 }
1439 }
1440
1441 impl Pool<RenderPassInfo, RenderPass> for NoopPool {
1442 fn resource(
1443 &mut self,
1444 _: RenderPassInfo,
1445 ) -> Result<crate::pool::Lease<RenderPass>, DriverError> {
1446 unreachable!()
1447 }
1448 }
1449
1450 fn bind_test_buffer(graph: &mut Graph) -> BufferNode {
1451 let index = graph.bind_stream_arg_resource(AnyResource::BufferArg(BufferInfo::device_mem(
1452 4,
1453 vk::BufferUsageFlags::TRANSFER_SRC,
1454 )));
1455 BufferNode::new(
1456 index,
1457 #[cfg(feature = "checked")]
1458 graph.graph_id(),
1459 )
1460 }
1461
1462 fn two_buffer_arg_stream() -> CommandStreamDraft<(BufferArg, BufferArg)> {
1463 CommandStream::finalize(|stream| {
1464 let first = stream.arg(BufferInfo::device_mem(
1465 4,
1466 vk::BufferUsageFlags::TRANSFER_SRC,
1467 ));
1468 let second = stream.arg(BufferInfo::device_mem(
1469 4,
1470 vk::BufferUsageFlags::TRANSFER_DST,
1471 ));
1472
1473 stream
1474 .begin_cmd()
1475 .resource_access(first, vk_sync::AccessType::TransferRead)
1476 .record_cmd(|_| {});
1477 stream
1478 .begin_cmd()
1479 .resource_access(second, vk_sync::AccessType::TransferWrite)
1480 .record_cmd(|_| {});
1481 stream
1482 .begin_cmd()
1483 .resource_access(first, vk_sync::AccessType::TransferRead)
1484 .record_cmd(|_| {});
1485
1486 (first, second)
1487 })
1488 }
1489
1490 #[test]
1491 fn empty_stream_can_be_inserted() {
1492 let stream = CommandStream::finalize(|_| {}).into_stream();
1493 let mut graph = Graph::new();
1494
1495 graph.insert_cmd_stream(&stream).finish();
1496 }
1497
1498 #[test]
1499 fn reusable_callback_can_prepare_stream() {
1500 let stream = CommandStream::finalize(|stream| {
1501 stream.begin_cmd().record_cmd(|_| {});
1502 })
1503 .into_stream();
1504 let mut graph = Graph::new();
1505
1506 graph.insert_cmd_stream(&stream).finish();
1507 assert_eq!(graph.cmds.len(), 1);
1508 }
1509
1510 #[test]
1511 fn graph_copy_wrapper_can_prepare_stream() {
1512 let _stream = CommandStream::finalize(|stream| {
1513 let src = stream.arg(BufferInfo::device_mem(
1514 4,
1515 vk::BufferUsageFlags::TRANSFER_SRC,
1516 ));
1517 let dst = stream.arg(BufferInfo::device_mem(
1518 4,
1519 vk::BufferUsageFlags::TRANSFER_DST,
1520 ));
1521
1522 stream.graph.copy_buffer(src, dst);
1523 })
1524 .into_stream();
1525 }
1526
1527 #[test]
1528 fn reusable_callback_can_prepare_optimized_stream() {
1529 let mut pool = NoopPool;
1530 let stream = CommandStream::prepare(&mut pool, |stream| {
1531 stream.begin_cmd().record_cmd(|_| {});
1532 })
1533 .expect("prepare stream");
1534 let mut graph = Graph::new();
1535
1536 graph.insert_cmd_stream(&stream).finish();
1537 assert_eq!(graph.cmds.len(), 1);
1538 }
1539
1540 #[test]
1541 fn unprepared_stream_expands_commands() {
1542 let stream = CommandStream::finalize(|stream| {
1543 stream.begin_cmd().record_cmd(|_| {});
1544 stream.begin_cmd().record_cmd(|_| {});
1545 })
1546 .into_stream();
1547 let mut graph = Graph::new();
1548
1549 graph.insert_cmd_stream(&stream).finish();
1550 assert_eq!(graph.cmds.len(), 2);
1551 }
1552
1553 #[test]
1554 fn prepared_stream_is_opaque_by_default() {
1555 let mut pool = NoopPool;
1556 let stream = CommandStream::prepare(&mut pool, |stream| {
1557 stream.begin_cmd().record_cmd(|_| {});
1558 stream.begin_cmd().record_cmd(|_| {});
1559 })
1560 .expect("prepare stream");
1561 let mut graph = Graph::new();
1562
1563 graph.insert_cmd_stream(&stream).finish();
1564 assert_eq!(graph.cmds.len(), 1);
1565 }
1566
1567 #[test]
1568 #[should_panic(
1569 expected = "distinct command stream arguments cannot bind to the same parent graph node"
1570 )]
1571 fn unprepared_stream_rejects_aliased_arguments() {
1572 let stream = two_buffer_arg_stream().into_stream();
1573 let mut graph = Graph::new();
1574 let buffer = bind_test_buffer(&mut graph);
1575
1576 graph
1577 .insert_cmd_stream(&stream)
1578 .with_arg(stream.args.0, buffer)
1579 .with_arg(stream.args.1, buffer)
1580 .finish();
1581 }
1582
1583 #[test]
1584 #[should_panic(
1585 expected = "distinct command stream arguments cannot bind to the same parent graph node"
1586 )]
1587 fn prepared_stream_rejects_aliased_arguments() {
1588 let mut pool = NoopPool;
1589 let stream = two_buffer_arg_stream()
1590 .prepare(&mut pool)
1591 .expect("prepare stream");
1592 let mut graph = Graph::new();
1593 let buffer = bind_test_buffer(&mut graph);
1594
1595 graph
1596 .insert_cmd_stream(&stream)
1597 .with_arg(stream.args.0, buffer)
1598 .with_arg(stream.args.1, buffer)
1599 .finish();
1600 }
1601
1602 #[test]
1603 fn same_argument_can_be_rebound() {
1604 let stream = two_buffer_arg_stream().into_stream();
1605 let mut graph = Graph::new();
1606 let first = bind_test_buffer(&mut graph);
1607 let second = bind_test_buffer(&mut graph);
1608
1609 graph
1610 .insert_cmd_stream(&stream)
1611 .with_arg(stream.args.0, first)
1612 .with_arg(stream.args.0, second)
1613 .with_arg(stream.args.1, first)
1614 .finish();
1615 }
1616
1617 #[test]
1618 fn image_arg_can_use_info_based_helpers() {
1619 let stream = CommandStream::finalize(|stream| {
1620 let output = stream.arg(ImageInfo::image_2d(
1621 1,
1622 1,
1623 vk::Format::R8G8B8A8_UNORM,
1624 vk::ImageUsageFlags::TRANSFER_DST,
1625 ));
1626
1627 stream.clear_color_image(output, [0.0, 0.0, 0.0, 0.0]);
1628
1629 output
1630 })
1631 .into_stream();
1632
1633 assert_eq!(stream.inner.args.len(), 1);
1634 }
1635
1636 #[test]
1637 #[should_panic(expected = "missing command stream argument")]
1638 fn missing_arg_panics_at_finish() {
1639 let stream = CommandStream::finalize(|stream| {
1640 stream.arg(ImageInfo::image_2d(
1641 1,
1642 1,
1643 vk::Format::R8G8B8A8_UNORM,
1644 vk::ImageUsageFlags::SAMPLED,
1645 ));
1646 })
1647 .into_stream();
1648 let mut graph = Graph::new();
1649
1650 graph.insert_cmd_stream(&stream).finish();
1651 }
1652
1653 #[test]
1654 #[cfg(feature = "checked")]
1655 #[should_panic(expected = "argument belongs to a different command stream")]
1656 fn wrong_stream_arg_panics_at_with_arg() {
1657 let stream_a = CommandStream::finalize(|stream| {
1658 stream.arg(ImageInfo::image_2d(
1659 1,
1660 1,
1661 vk::Format::R8G8B8A8_UNORM,
1662 vk::ImageUsageFlags::SAMPLED,
1663 ))
1664 })
1665 .into_stream();
1666 let stream_b = CommandStream::finalize(|stream| {
1667 stream.arg(ImageInfo::image_2d(
1668 1,
1669 1,
1670 vk::Format::R8G8B8A8_UNORM,
1671 vk::ImageUsageFlags::SAMPLED,
1672 ))
1673 })
1674 .into_stream();
1675 let mut graph = Graph::new();
1676
1677 graph
1678 .insert_cmd_stream(&stream_a)
1679 .with_arg(stream_b.args, AnyImageNode::from(stream_b.args))
1680 .finish();
1681 }
1682
1683 #[test]
1684 #[should_panic(expected = "stream argument cannot be supplied as a parent graph node")]
1685 fn stream_arg_cannot_bind_as_parent_graph_node() {
1686 let stream = CommandStream::finalize(|stream| {
1687 stream.arg(ImageInfo::image_2d(
1688 1,
1689 1,
1690 vk::Format::R8G8B8A8_UNORM,
1691 vk::ImageUsageFlags::SAMPLED,
1692 ))
1693 })
1694 .into_stream();
1695 let mut graph = Graph::new();
1696
1697 graph
1698 .insert_cmd_stream(&stream)
1699 .with_arg(stream.args, AnyImageNode::from(stream.args))
1700 .finish();
1701 }
1702
1703 #[test]
1704 #[should_panic(expected = "command stream contains a one-shot callback")]
1705 fn one_shot_callback_cannot_prepare_stream() {
1706 let _ = CommandStream::finalize(|stream| {
1707 stream.graph.begin_cmd().record_cmd(|_| {});
1708 });
1709 }
1710}