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> {
1061 pub(crate) bindings: Vec<Option<usize>>,
1062 pub(crate) graph: &'a mut Graph,
1063 pub(crate) stream: &'a CommandStream<A>,
1064}
1065
1066impl<'a, A> CommandStreamRun<'a, A> {
1067 pub fn with_arg<T, N>(mut self, arg: StreamArg<T>, node: N) -> Self
1069 where
1070 N: StreamArgBindable<T>,
1071 {
1072 #[cfg(feature = "checked")]
1073 assert!(
1074 arg.stream_id == self.stream.inner.stream_id,
1075 "argument belongs to a different command stream"
1076 );
1077 node.assert_parent_node();
1078 self.graph.assert_node_owner(&node);
1079 self.bindings[arg.arg_index] = Some(node.index());
1080 self
1081 }
1082
1083 pub fn finish(self) -> &'a mut Graph {
1085 #[cfg(feature = "checked")]
1086 assert!(
1087 self.bindings.iter().all(Option::is_some),
1088 "missing command stream argument"
1089 );
1090
1091 self.graph
1092 .append_command_stream(self.stream, &self.bindings);
1093 self.graph
1094 }
1095}
1096
1097impl Graph {
1098 pub fn insert_cmd_stream<'a, A>(
1103 &'a mut self,
1104 stream: &'a CommandStream<A>,
1105 ) -> CommandStreamRun<'a, A> {
1106 CommandStreamRun {
1107 bindings: vec![None; stream.inner.args.len()],
1108 graph: self,
1109 stream,
1110 }
1111 }
1112}
1113
1114impl Graph {
1115 pub(crate) fn append_command_stream<A>(
1116 &mut self,
1117 stream: &CommandStream<A>,
1118 bindings: &[Option<usize>],
1119 ) {
1120 if stream.inner.prepared {
1121 self.append_prepared_command_stream(stream, bindings);
1122 } else {
1123 self.append_unprepared_command_stream(stream, bindings);
1124 }
1125 }
1126
1127 fn append_unprepared_command_stream<A>(
1128 &mut self,
1129 stream: &CommandStream<A>,
1130 bindings: &[Option<usize>],
1131 ) {
1132 let submission = stream
1133 .inner
1134 .submission
1135 .lock()
1136 .expect("poisoned command stream submission");
1137 let stream_graph = submission.graph();
1138 let mut arg_by_node = HashMap::new();
1139
1140 for (arg_idx, &node_idx) in stream.inner.arg_nodes.iter().enumerate() {
1141 arg_by_node.insert(node_idx, arg_idx);
1142 }
1143
1144 let mut node_map = Vec::with_capacity(stream_graph.resources.len());
1145 for (node_idx, resource) in stream_graph.resources.iter().enumerate() {
1146 if let Some(&arg_idx) = arg_by_node.get(&node_idx) {
1147 node_map.push(bindings[arg_idx].expect("missing command stream argument"));
1148 } else {
1149 node_map.push(self.resources.bind(resource.clone()));
1150 }
1151 }
1152
1153 for cmd in &stream_graph.cmds {
1154 let mut cmd = cmd.clone();
1155 cmd.remap_nodes(&node_map);
1156
1157 #[cfg(feature = "checked")]
1158 for exec in &mut cmd.execs {
1159 exec.stream_graph_id = Some(stream.inner.graph_id);
1160 }
1161
1162 self.cmds.push(cmd);
1163 }
1164 }
1165
1166 fn append_prepared_command_stream<A>(
1167 &mut self,
1168 stream: &CommandStream<A>,
1169 bindings: &[Option<usize>],
1170 ) {
1171 let stream_scope_id = next_stream_scope_id();
1172 let submission = stream
1173 .inner
1174 .submission
1175 .lock()
1176 .expect("poisoned command stream submission");
1177 let stream_graph = submission.graph();
1178 let mut arg_by_node = HashMap::new();
1179
1180 for (arg_idx, &node_idx) in stream.inner.arg_nodes.iter().enumerate() {
1181 arg_by_node.insert(node_idx, arg_idx);
1182 }
1183
1184 let mut cmd = self.begin_cmd().debug_name("command stream");
1185 cmd.set_stream_scope_id(stream_scope_id);
1186
1187 for stream_cmd in &stream_graph.cmds {
1188 for (node_idx, accesses) in stream_cmd
1189 .execs
1190 .iter()
1191 .flat_map(|exec| exec.accesses.iter())
1192 {
1193 let Some(&arg_idx) = arg_by_node.get(&node_idx) else {
1194 continue;
1195 };
1196 let parent_node_idx = bindings[arg_idx].expect("missing command stream argument");
1197
1198 for access in accesses {
1199 cmd.push_subresource_access_index(
1200 parent_node_idx,
1201 access.subresource,
1202 access.access,
1203 );
1204 }
1205 }
1206 }
1207
1208 drop(submission);
1209
1210 let stream = Arc::clone(&stream.inner);
1211 let bindings = bindings.to_vec();
1212 cmd.record_stream(move |cmd| {
1213 let submission = stream
1214 .submission
1215 .lock()
1216 .expect("poisoned command stream submission");
1217 let stream_graph = submission.graph();
1218 let mut arg_by_node = HashMap::new();
1219
1220 for (arg_idx, &node_idx) in stream.arg_nodes.iter().enumerate() {
1221 arg_by_node.insert(node_idx, arg_idx);
1222 }
1223
1224 let resources = stream_graph
1225 .resources
1226 .iter()
1227 .enumerate()
1228 .map(|(node_idx, resource)| {
1229 if let Some(&arg_idx) = arg_by_node.get(&node_idx) {
1230 cmd.clone_resource_at(
1231 bindings[arg_idx].expect("missing command stream argument"),
1232 )
1233 } else {
1234 resource.clone()
1235 }
1236 })
1237 .collect();
1238 drop(submission);
1239
1240 stream
1241 .submission
1242 .lock()
1243 .expect("poisoned command stream submission")
1244 .record_prepared_command_stream(&cmd, ResourceMap::from_resources(resources))
1245 .expect("unable to record command stream");
1246 });
1247 }
1248}
1249
1250#[allow(private_bounds)]
1252#[doc(hidden)]
1253pub trait StreamArgInfo: stream_private::StreamArgInfoSealed {
1254 type Arg;
1256
1257 #[doc(hidden)]
1258 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg;
1259}
1260
1261#[allow(private_bounds)]
1263#[doc(hidden)]
1264pub trait StreamArgBindable<T>: stream_private::StreamArgBindableSealed<T> + Node {
1265 #[doc(hidden)]
1266 fn assert_parent_node(&self);
1267}
1268
1269#[allow(private_bounds)]
1271#[doc(hidden)]
1272pub trait StreamResourceNode: stream_private::StreamResourceNodeSealed + Node {}
1273
1274mod stream_private {
1275 pub trait StreamArgInfoSealed {}
1276
1277 pub trait StreamArgBindableSealed<T> {}
1278
1279 pub trait StreamResourceNodeSealed {}
1280
1281 pub trait StreamPipelineSealed {}
1282}
1283
1284macro_rules! stream_arg_info {
1285 ($info:ty, $builder:ty, $variant:ident, $arg:ty) => {
1286 impl stream_private::StreamArgInfoSealed for $info {}
1287
1288 impl StreamArgInfo for $info {
1289 type Arg = $arg;
1290
1291 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg {
1292 let data = StreamArgData::$variant(self);
1293 let arg_index = stream.push_arg(data);
1294 let node_index = stream.bind_arg_resource(data);
1295 stream.arg_nodes.push(node_index);
1296 StreamArg::new(
1297 arg_index,
1298 node_index,
1299 #[cfg(feature = "checked")]
1300 stream.stream_id,
1301 #[cfg(feature = "checked")]
1302 stream.graph.graph_id(),
1303 )
1304 }
1305 }
1306
1307 impl stream_private::StreamArgInfoSealed for $builder {}
1308
1309 impl StreamArgInfo for $builder {
1310 type Arg = $arg;
1311
1312 fn bind_stream_arg(self, stream: &mut CommandStreamMut) -> Self::Arg {
1313 self.build().bind_stream_arg(stream)
1314 }
1315 }
1316 };
1317}
1318
1319stream_arg_info!(
1320 AccelerationStructureInfo,
1321 AccelerationStructureInfoBuilder,
1322 AccelerationStructure,
1323 AccelerationStructureArg
1324);
1325stream_arg_info!(BufferInfo, BufferInfoBuilder, Buffer, BufferArg);
1326stream_arg_info!(ImageInfo, ImageInfoBuilder, Image, ImageArg);
1327
1328macro_rules! stream_arg_bindable {
1329 ($resource:ty => $($node:ty),+ $(,)?) => {
1330 $(
1331 impl stream_private::StreamArgBindableSealed<$resource> for $node {}
1332
1333 impl StreamArgBindable<$resource> for $node {
1334 fn assert_parent_node(&self) {}
1335 }
1336 )+
1337 };
1338}
1339
1340stream_arg_bindable!(
1341 AccelerationStructure => AccelerationStructureNode,
1342 AccelerationStructureLeaseNode,
1343);
1344stream_arg_bindable!(Buffer => BufferNode, BufferLeaseNode);
1345stream_arg_bindable!(Image => ImageNode, ImageLeaseNode, SwapchainImageNode);
1346
1347impl stream_private::StreamArgBindableSealed<AccelerationStructure>
1348 for AnyAccelerationStructureNode
1349{
1350}
1351
1352impl StreamArgBindable<AccelerationStructure> for AnyAccelerationStructureNode {
1353 fn assert_parent_node(&self) {
1354 assert!(
1355 !matches!(self, Self::Arg(_)),
1356 "stream argument cannot be supplied as a parent graph node"
1357 );
1358 }
1359}
1360
1361impl stream_private::StreamArgBindableSealed<Buffer> for AnyBufferNode {}
1362
1363impl StreamArgBindable<Buffer> for AnyBufferNode {
1364 fn assert_parent_node(&self) {
1365 assert!(
1366 !matches!(self, Self::Arg(_)),
1367 "stream argument cannot be supplied as a parent graph node"
1368 );
1369 }
1370}
1371
1372impl stream_private::StreamArgBindableSealed<Image> for AnyImageNode {}
1373
1374impl StreamArgBindable<Image> for AnyImageNode {
1375 fn assert_parent_node(&self) {
1376 assert!(
1377 !matches!(self, Self::Arg(_)),
1378 "stream argument cannot be supplied as a parent graph node"
1379 );
1380 }
1381}
1382
1383macro_rules! stream_resource_node {
1384 ($($node:ty),+ $(,)?) => {
1385 $(
1386 impl stream_private::StreamResourceNodeSealed for $node {}
1387 impl StreamResourceNode for $node {}
1388 )+
1389 };
1390}
1391
1392stream_resource_node!(
1393 AccelerationStructureNode,
1394 AccelerationStructureLeaseNode,
1395 BufferNode,
1396 BufferLeaseNode,
1397 ImageNode,
1398 ImageLeaseNode,
1399 SwapchainImageNode,
1400);
1401
1402#[cfg(test)]
1403mod tests {
1404 use super::*;
1405 use crate::{
1406 driver::{
1407 buffer::BufferInfo,
1408 descriptor_set::{DescriptorPool, DescriptorPoolInfo},
1409 render_pass::{RenderPass, RenderPassInfo},
1410 },
1411 pool::Pool,
1412 };
1413
1414 struct NoopPool;
1415
1416 impl Pool<DescriptorPoolInfo, DescriptorPool> for NoopPool {
1417 fn resource(
1418 &mut self,
1419 _: DescriptorPoolInfo,
1420 ) -> Result<crate::pool::Lease<DescriptorPool>, DriverError> {
1421 unreachable!()
1422 }
1423 }
1424
1425 impl Pool<RenderPassInfo, RenderPass> for NoopPool {
1426 fn resource(
1427 &mut self,
1428 _: RenderPassInfo,
1429 ) -> Result<crate::pool::Lease<RenderPass>, DriverError> {
1430 unreachable!()
1431 }
1432 }
1433
1434 #[test]
1435 fn empty_stream_can_be_inserted() {
1436 let stream = CommandStream::finalize(|_| {}).into_stream();
1437 let mut graph = Graph::new();
1438
1439 graph.insert_cmd_stream(&stream).finish();
1440 }
1441
1442 #[test]
1443 fn reusable_callback_can_prepare_stream() {
1444 let stream = CommandStream::finalize(|stream| {
1445 stream.begin_cmd().record_cmd(|_| {});
1446 })
1447 .into_stream();
1448 let mut graph = Graph::new();
1449
1450 graph.insert_cmd_stream(&stream).finish();
1451 assert_eq!(graph.cmds.len(), 1);
1452 }
1453
1454 #[test]
1455 fn graph_copy_wrapper_can_prepare_stream() {
1456 let _stream = CommandStream::finalize(|stream| {
1457 let src = stream.arg(BufferInfo::device_mem(
1458 4,
1459 vk::BufferUsageFlags::TRANSFER_SRC,
1460 ));
1461 let dst = stream.arg(BufferInfo::device_mem(
1462 4,
1463 vk::BufferUsageFlags::TRANSFER_DST,
1464 ));
1465
1466 stream.graph.copy_buffer(src, dst);
1467 })
1468 .into_stream();
1469 }
1470
1471 #[test]
1472 fn reusable_callback_can_prepare_optimized_stream() {
1473 let mut pool = NoopPool;
1474 let stream = CommandStream::prepare(&mut pool, |stream| {
1475 stream.begin_cmd().record_cmd(|_| {});
1476 })
1477 .expect("prepare stream");
1478 let mut graph = Graph::new();
1479
1480 graph.insert_cmd_stream(&stream).finish();
1481 assert_eq!(graph.cmds.len(), 1);
1482 }
1483
1484 #[test]
1485 fn unprepared_stream_expands_commands() {
1486 let stream = CommandStream::finalize(|stream| {
1487 stream.begin_cmd().record_cmd(|_| {});
1488 stream.begin_cmd().record_cmd(|_| {});
1489 })
1490 .into_stream();
1491 let mut graph = Graph::new();
1492
1493 graph.insert_cmd_stream(&stream).finish();
1494 assert_eq!(graph.cmds.len(), 2);
1495 }
1496
1497 #[test]
1498 fn prepared_stream_is_opaque_by_default() {
1499 let mut pool = NoopPool;
1500 let stream = CommandStream::prepare(&mut pool, |stream| {
1501 stream.begin_cmd().record_cmd(|_| {});
1502 stream.begin_cmd().record_cmd(|_| {});
1503 })
1504 .expect("prepare stream");
1505 let mut graph = Graph::new();
1506
1507 graph.insert_cmd_stream(&stream).finish();
1508 assert_eq!(graph.cmds.len(), 1);
1509 }
1510
1511 #[test]
1512 fn image_arg_can_use_info_based_helpers() {
1513 let stream = CommandStream::finalize(|stream| {
1514 let output = stream.arg(ImageInfo::image_2d(
1515 1,
1516 1,
1517 vk::Format::R8G8B8A8_UNORM,
1518 vk::ImageUsageFlags::TRANSFER_DST,
1519 ));
1520
1521 stream.clear_color_image(output, [0.0, 0.0, 0.0, 0.0]);
1522
1523 output
1524 })
1525 .into_stream();
1526
1527 assert_eq!(stream.inner.args.len(), 1);
1528 }
1529
1530 #[test]
1531 #[should_panic(expected = "missing command stream argument")]
1532 fn missing_arg_panics_at_finish() {
1533 let stream = CommandStream::finalize(|stream| {
1534 stream.arg(ImageInfo::image_2d(
1535 1,
1536 1,
1537 vk::Format::R8G8B8A8_UNORM,
1538 vk::ImageUsageFlags::SAMPLED,
1539 ));
1540 })
1541 .into_stream();
1542 let mut graph = Graph::new();
1543
1544 graph.insert_cmd_stream(&stream).finish();
1545 }
1546
1547 #[test]
1548 #[cfg(feature = "checked")]
1549 #[should_panic(expected = "argument belongs to a different command stream")]
1550 fn wrong_stream_arg_panics_at_with_arg() {
1551 let stream_a = CommandStream::finalize(|stream| {
1552 stream.arg(ImageInfo::image_2d(
1553 1,
1554 1,
1555 vk::Format::R8G8B8A8_UNORM,
1556 vk::ImageUsageFlags::SAMPLED,
1557 ))
1558 })
1559 .into_stream();
1560 let stream_b = CommandStream::finalize(|stream| {
1561 stream.arg(ImageInfo::image_2d(
1562 1,
1563 1,
1564 vk::Format::R8G8B8A8_UNORM,
1565 vk::ImageUsageFlags::SAMPLED,
1566 ))
1567 })
1568 .into_stream();
1569 let mut graph = Graph::new();
1570
1571 graph
1572 .insert_cmd_stream(&stream_a)
1573 .with_arg(stream_b.args, AnyImageNode::from(stream_b.args))
1574 .finish();
1575 }
1576
1577 #[test]
1578 #[should_panic(expected = "stream argument cannot be supplied as a parent graph node")]
1579 fn stream_arg_cannot_bind_as_parent_graph_node() {
1580 let stream = CommandStream::finalize(|stream| {
1581 stream.arg(ImageInfo::image_2d(
1582 1,
1583 1,
1584 vk::Format::R8G8B8A8_UNORM,
1585 vk::ImageUsageFlags::SAMPLED,
1586 ))
1587 })
1588 .into_stream();
1589 let mut graph = Graph::new();
1590
1591 graph
1592 .insert_cmd_stream(&stream)
1593 .with_arg(stream.args, AnyImageNode::from(stream.args))
1594 .finish();
1595 }
1596
1597 #[test]
1598 #[should_panic(expected = "command stream contains a one-shot callback")]
1599 fn one_shot_callback_cannot_prepare_stream() {
1600 let _ = CommandStream::finalize(|stream| {
1601 stream.graph.begin_cmd().record_cmd(|_| {});
1602 });
1603 }
1604}