rafx_framework/graph/
graph_builder.rs

1use super::*;
2use crate::render_features::{RenderPhase, RenderPhaseIndex};
3use crate::resources::{ImageViewResource, ResourceArc};
4use crate::BufferResource;
5use fnv::{FnvHashMap, FnvHashSet};
6use rafx_api::{
7    RafxCmdCopyBufferToBufferParams, RafxCmdCopyTextureToTextureParams, RafxColorClearValue,
8    RafxDepthStencilClearValue, RafxLoadOp, RafxResourceState, RafxResourceType, RafxResult,
9};
10
11#[derive(Copy, Clone)]
12pub enum RenderGraphQueue {
13    DefaultGraphics,
14    Index(u32),
15}
16
17/// An image that is being provided to the render graph that can be read/written by the graph
18#[derive(Debug)]
19pub struct RenderGraphExternalImage {
20    pub external_image_id: RenderGraphExternalImageId,
21    pub specification: RenderGraphImageSpecification,
22    pub view_options: RenderGraphImageViewOptions,
23    pub image_resource: ResourceArc<ImageViewResource>,
24    pub image_resource_index: usize,
25
26    // These are set when calling read_external_image/write_external_image
27    pub input_usage: Option<RenderGraphImageUsageId>,
28    pub output_usage: Option<RenderGraphImageUsageId>,
29
30    //TODO: Use initial state
31    #[allow(dead_code)]
32    pub(super) initial_state: RafxResourceState,
33    pub(super) final_state: RafxResourceState,
34}
35
36/// A buffer that is being provided to the render graph that can be read/written by the graph
37#[derive(Debug)]
38pub struct RenderGraphExternalBuffer {
39    pub external_buffer_id: RenderGraphExternalBufferId,
40    pub specification: RenderGraphBufferSpecification,
41    pub buffer_resource: ResourceArc<BufferResource>,
42    pub buffer_resource_index: usize,
43
44    pub input_usage: Option<RenderGraphBufferUsageId>,
45    pub output_usage: Option<RenderGraphBufferUsageId>,
46
47    //TODO: Use initial/final state
48    #[allow(dead_code)]
49    pub(super) initial_state: RafxResourceState,
50    #[allow(dead_code)]
51    pub(super) final_state: RafxResourceState,
52}
53
54/// A collection of nodes and resources. Nodes represent an event or process that will occur at
55/// a certain time. (For now, they just represent subpasses that may be merged with each other.)
56/// Resources represent images and buffers that may be read/written by nodes.
57#[derive(Default)]
58pub struct RenderGraphBuilder {
59    /// Nodes that have been registered in the graph
60    pub(super) nodes: Vec<RenderGraphNode>,
61
62    /// Image resources that have been registered in the graph. These resources are "virtual" until
63    /// the graph is scheduled. In other words, we don't necessarily allocate an image for every
64    /// resource as some resources can share the same image internally if their lifetime don't
65    /// overlap. Additionally, a resource can be bound to input and output images. If this is the
66    /// case, we will try to use those images rather than creating new ones.
67    pub(super) image_resources: Vec<RenderGraphImageResource>,
68    pub(super) buffer_resources: Vec<RenderGraphBufferResource>,
69
70    /// All read/write accesses to images. Image writes create new "versions" of the image. So all
71    /// image versions have one writer and 0 or more readers. This indirectly defines the order of
72    /// execution for the graph.
73    pub(super) image_usages: Vec<RenderGraphImageUsage>,
74    pub(super) buffer_usages: Vec<RenderGraphBufferUsage>,
75
76    /// Images that are passed into the graph that can be read/written by the graph
77    pub(super) external_images: Vec<RenderGraphExternalImage>,
78    pub(super) external_buffers: Vec<RenderGraphExternalBuffer>,
79
80    //
81    // Callbacks
82    //
83    pub(super) visit_node_callbacks:
84        FnvHashMap<RenderGraphNodeId, RenderGraphNodeVisitNodeCallback>,
85    pub(super) render_phase_dependencies:
86        FnvHashMap<RenderGraphNodeId, FnvHashSet<RenderPhaseIndex>>,
87}
88
89impl RenderGraphBuilder {
90    //NOTE: While the image aspect flags may seem redundant with subresource_range here, the
91    // subresource_range should indicate the image view's supported aspects and the provided
92    // image aspect flags the aspects that are actually being used
93    pub(super) fn add_image_usage(
94        &mut self,
95        user: RenderGraphImageUser,
96        version: RenderGraphImageVersionId,
97        usage_type: RenderGraphImageUsageType,
98        view_options: RenderGraphImageViewOptions,
99    ) -> RenderGraphImageUsageId {
100        let usage_id = RenderGraphImageUsageId(self.image_usages.len());
101
102        self.image_usages.push(RenderGraphImageUsage {
103            user,
104            usage_type,
105            version,
106            view_options,
107        });
108        usage_id
109    }
110
111    // Add an image that can be used by nodes
112    pub(super) fn add_image_create(
113        &mut self,
114        create_node: RenderGraphNodeId,
115        constraint: RenderGraphImageConstraint,
116        view_options: RenderGraphImageViewOptions,
117    ) -> RenderGraphImageUsageId {
118        let version_id = RenderGraphImageVersionId {
119            index: self.image_resources.len(),
120            version: 0,
121        };
122        let usage_id = self.add_image_usage(
123            RenderGraphImageUser::Node(create_node),
124            version_id,
125            RenderGraphImageUsageType::Create,
126            view_options,
127        );
128
129        let mut resource = RenderGraphImageResource::new();
130
131        let version_info = RenderGraphImageResourceVersionInfo::new(create_node, usage_id);
132        resource.versions.push(version_info);
133
134        // Add it to the graph
135        self.image_resources.push(resource);
136
137        self.nodes[create_node.0]
138            .image_creates
139            .push(RenderGraphImageCreate {
140                //image: image_id,
141                image: usage_id,
142                constraint,
143            });
144
145        usage_id
146    }
147
148    pub(super) fn add_image_read(
149        &mut self,
150        read_node: RenderGraphNodeId,
151        image: RenderGraphImageUsageId,
152        constraint: RenderGraphImageConstraint,
153        view_options: RenderGraphImageViewOptions,
154    ) -> RenderGraphImageUsageId {
155        let version_id = self.image_usages[image.0].version;
156
157        let usage_id = self.add_image_usage(
158            RenderGraphImageUser::Node(read_node),
159            version_id,
160            RenderGraphImageUsageType::Read,
161            view_options,
162        );
163
164        self.image_resources[version_id.index].versions[version_id.version]
165            .add_read_usage(usage_id);
166
167        self.nodes[read_node.0]
168            .image_reads
169            .push(RenderGraphImageRead {
170                image: usage_id,
171                constraint,
172            });
173
174        usage_id
175    }
176
177    pub(super) fn add_image_modify(
178        &mut self,
179        modify_node: RenderGraphNodeId,
180        image: RenderGraphImageUsageId,
181        constraint: RenderGraphImageConstraint,
182        view_options: RenderGraphImageViewOptions,
183    ) -> (RenderGraphImageUsageId, RenderGraphImageUsageId) {
184        let read_version_id = self.image_usages[image.0].version;
185
186        let read_usage_id = self.add_image_usage(
187            RenderGraphImageUser::Node(modify_node),
188            read_version_id,
189            RenderGraphImageUsageType::ModifyRead,
190            view_options.clone(),
191        );
192
193        self.image_resources[read_version_id.index].versions[read_version_id.version]
194            .add_read_usage(read_usage_id);
195
196        // Create a new version and add it to the image
197        let version = self.image_resources[read_version_id.index].versions.len();
198        let write_version_id = RenderGraphImageVersionId {
199            index: read_version_id.index,
200            version,
201        };
202        let write_usage_id = self.add_image_usage(
203            RenderGraphImageUser::Node(modify_node),
204            write_version_id,
205            RenderGraphImageUsageType::ModifyWrite,
206            view_options,
207        );
208
209        let version_info = RenderGraphImageResourceVersionInfo::new(modify_node, write_usage_id);
210        self.image_resources[read_version_id.index]
211            .versions
212            .push(version_info);
213
214        self.nodes[modify_node.0]
215            .image_modifies
216            .push(RenderGraphImageModify {
217                input: read_usage_id,
218                output: write_usage_id,
219                constraint,
220            });
221
222        (read_usage_id, write_usage_id)
223    }
224
225    fn set_color_attachment(
226        &mut self,
227        node: RenderGraphNodeId,
228        color_attachment_index: usize,
229        color_attachment: RenderGraphPassColorAttachmentInfo,
230    ) {
231        assert_eq!(self.node(node).kind, RenderGraphNodeKind::Renderpass);
232
233        //TODO: Check constraint does not conflict with the matching resolve attachment, if there is one
234        let node_color_attachments = &mut self.nodes[node.0].color_attachments;
235        if node_color_attachments.len() <= color_attachment_index {
236            node_color_attachments.resize_with(color_attachment_index + 1, || None);
237        }
238
239        assert!(node_color_attachments[color_attachment_index].is_none());
240        node_color_attachments[color_attachment_index] = Some(color_attachment);
241    }
242
243    fn set_depth_attachment(
244        &mut self,
245        node: RenderGraphNodeId,
246        depth_attachment: RenderGraphPassDepthAttachmentInfo,
247    ) {
248        assert_eq!(self.node(node).kind, RenderGraphNodeKind::Renderpass);
249
250        let node_depth_attachment = &mut self.nodes[node.0].depth_attachment;
251        assert!(node_depth_attachment.is_none());
252        *node_depth_attachment = Some(depth_attachment);
253    }
254
255    fn set_resolve_attachment(
256        &mut self,
257        node: RenderGraphNodeId,
258        resolve_attachment_index: usize,
259        resolve_attachment: RenderGraphPassResolveAttachmentInfo,
260    ) {
261        assert_eq!(self.node(node).kind, RenderGraphNodeKind::Renderpass);
262
263        //TODO: Check constraint is non-MSAA and is not conflicting with the matching color attachment, if there is one
264        let node_resolve_attachments = &mut self.nodes[node.0].resolve_attachments;
265        if node_resolve_attachments.len() <= resolve_attachment_index {
266            node_resolve_attachments.resize_with(resolve_attachment_index + 1, || None);
267        }
268
269        assert!(node_resolve_attachments[resolve_attachment_index].is_none());
270        node_resolve_attachments[resolve_attachment_index] = Some(resolve_attachment);
271    }
272
273    /// Create an image but do not use it (may be passed around and used elsewhere)
274    pub fn create_unattached_image(
275        &mut self,
276        create_node: RenderGraphNodeId,
277        constraint: RenderGraphImageConstraint,
278        view_options: RenderGraphImageViewOptions,
279    ) -> RenderGraphImageUsageId {
280        self.add_image_create(create_node, constraint, view_options)
281    }
282
283    /// Create a new image and use it as a writable color attachment in a renderpass
284    pub fn create_color_attachment(
285        &mut self,
286        node: RenderGraphNodeId,
287        color_attachment_index: usize,
288        clear_color_value: Option<RafxColorClearValue>,
289        mut constraint: RenderGraphImageConstraint,
290        view_options: RenderGraphImageViewOptions,
291    ) -> RenderGraphImageUsageId {
292        constraint.resource_type |= RafxResourceType::RENDER_TARGET_COLOR;
293
294        // Add the read to the graph
295        let create_image = self.add_image_create(node, constraint, view_options);
296
297        self.set_color_attachment(
298            node,
299            color_attachment_index,
300            RenderGraphPassColorAttachmentInfo {
301                attachment_type: RenderGraphPassAttachmentType::Create,
302                clear_color_value,
303                read_image: None,
304                write_image: Some(create_image),
305            },
306        );
307
308        create_image
309    }
310
311    /// Create a new image and use it as a writable depth attachment in a renderpass
312    pub fn create_depth_attachment(
313        &mut self,
314        node: RenderGraphNodeId,
315        clear_depth_stencil_value: Option<RafxDepthStencilClearValue>,
316        constraint: RenderGraphImageConstraint,
317        view_options: RenderGraphImageViewOptions,
318    ) -> RenderGraphImageUsageId {
319        self.create_depth_stencil_attachment(
320            node,
321            clear_depth_stencil_value,
322            constraint,
323            view_options,
324            true,
325            false,
326        )
327    }
328
329    /// Create a new image and use it as a writable depth/stencil attachment in a renderpass
330    pub fn create_depth_stencil_attachment(
331        &mut self,
332        node: RenderGraphNodeId,
333        clear_depth_stencil_value: Option<RafxDepthStencilClearValue>,
334        mut constraint: RenderGraphImageConstraint,
335        view_options: RenderGraphImageViewOptions,
336        has_depth: bool,
337        has_stencil: bool,
338    ) -> RenderGraphImageUsageId {
339        constraint.resource_type |= RafxResourceType::RENDER_TARGET_DEPTH_STENCIL;
340
341        // Add the read to the graph
342        let create_image = self.add_image_create(node, constraint, view_options);
343
344        self.set_depth_attachment(
345            node,
346            RenderGraphPassDepthAttachmentInfo {
347                attachment_type: RenderGraphPassAttachmentType::Create,
348                clear_depth_stencil_value,
349                read_image: None,
350                write_image: Some(create_image),
351                has_depth,
352                has_stencil,
353            },
354        );
355
356        create_image
357    }
358
359    /// Create a new image and use it as a resolve attachment in a renderpass
360    pub fn create_resolve_attachment(
361        &mut self,
362        node: RenderGraphNodeId,
363        resolve_attachment_index: usize,
364        mut constraint: RenderGraphImageConstraint,
365        view_options: RenderGraphImageViewOptions,
366    ) -> RenderGraphImageUsageId {
367        constraint.resource_type |= RafxResourceType::RENDER_TARGET_COLOR;
368
369        let create_image = self.add_image_create(node, constraint, view_options);
370
371        self.set_resolve_attachment(
372            node,
373            resolve_attachment_index,
374            RenderGraphPassResolveAttachmentInfo {
375                attachment_type: RenderGraphPassAttachmentType::Create,
376                write_image: create_image,
377            },
378        );
379
380        create_image
381    }
382
383    /// Use the given image as a read-only color attachment in a renderpass
384    pub fn read_color_attachment(
385        &mut self,
386        node: RenderGraphNodeId,
387        image: RenderGraphImageUsageId,
388        color_attachment_index: usize,
389        mut constraint: RenderGraphImageConstraint,
390        view_options: RenderGraphImageViewOptions,
391    ) {
392        constraint.resource_type |= RafxResourceType::RENDER_TARGET_COLOR;
393
394        // Add the read to the graph
395        let read_image = self.add_image_read(node, image, constraint, view_options);
396
397        self.set_color_attachment(
398            node,
399            color_attachment_index,
400            RenderGraphPassColorAttachmentInfo {
401                attachment_type: RenderGraphPassAttachmentType::Read,
402                clear_color_value: None,
403                read_image: Some(read_image),
404                write_image: None,
405            },
406        );
407    }
408
409    /// Use the given image as a read-only depth attachment in a renderpass
410    pub fn read_depth_attachment(
411        &mut self,
412        node: RenderGraphNodeId,
413        image: RenderGraphImageUsageId,
414        constraint: RenderGraphImageConstraint,
415        view_options: RenderGraphImageViewOptions,
416    ) {
417        self.read_depth_stencil_attachment(node, image, constraint, view_options, true, false);
418    }
419
420    /// Use the given image as a read-only depth/stencil attachment in a renderpass
421    pub fn read_depth_stencil_attachment(
422        &mut self,
423        node: RenderGraphNodeId,
424        image: RenderGraphImageUsageId,
425        mut constraint: RenderGraphImageConstraint,
426        view_options: RenderGraphImageViewOptions,
427        has_depth: bool,
428        has_stencil: bool,
429    ) {
430        constraint.resource_type |= RafxResourceType::RENDER_TARGET_DEPTH_STENCIL;
431
432        // Add the read to the graph
433        let read_image = self.add_image_read(node, image, constraint, view_options);
434
435        self.set_depth_attachment(
436            node,
437            RenderGraphPassDepthAttachmentInfo {
438                attachment_type: RenderGraphPassAttachmentType::Read,
439                clear_depth_stencil_value: None,
440                read_image: Some(read_image),
441                write_image: None,
442                has_depth,
443                has_stencil,
444            },
445        );
446    }
447
448    /// Use the given image as a writable color attachment in a renderpass
449    pub fn modify_color_attachment(
450        &mut self,
451        node: RenderGraphNodeId,
452        image: RenderGraphImageUsageId,
453        color_attachment_index: usize,
454        clear_color_value: Option<RafxColorClearValue>,
455        mut constraint: RenderGraphImageConstraint,
456        view_options: RenderGraphImageViewOptions,
457    ) -> RenderGraphImageUsageId {
458        constraint.resource_type |= RafxResourceType::RENDER_TARGET_COLOR;
459
460        // Add the read to the graph
461        let (read_image, write_image) =
462            self.add_image_modify(node, image, constraint, view_options);
463
464        self.set_color_attachment(
465            node,
466            color_attachment_index,
467            RenderGraphPassColorAttachmentInfo {
468                attachment_type: RenderGraphPassAttachmentType::Modify,
469                clear_color_value,
470                read_image: Some(read_image),
471                write_image: Some(write_image),
472            },
473        );
474
475        write_image
476    }
477
478    /// Use the given image as a writable depth attachment in a renderpass
479    pub fn modify_depth_attachment(
480        &mut self,
481        node: RenderGraphNodeId,
482        image: RenderGraphImageUsageId,
483        clear_depth_stencil_value: Option<RafxDepthStencilClearValue>,
484        mut constraint: RenderGraphImageConstraint,
485        view_options: RenderGraphImageViewOptions,
486    ) -> RenderGraphImageUsageId {
487        constraint.resource_type |= RafxResourceType::RENDER_TARGET_DEPTH_STENCIL;
488
489        // Add the read to the graph
490        let (read_image, write_image) =
491            self.add_image_modify(node, image, constraint, view_options);
492
493        self.set_depth_attachment(
494            node,
495            RenderGraphPassDepthAttachmentInfo {
496                attachment_type: RenderGraphPassAttachmentType::Modify,
497                clear_depth_stencil_value,
498                read_image: Some(read_image),
499                write_image: Some(write_image),
500                has_depth: true,
501                has_stencil: false,
502            },
503        );
504
505        write_image
506    }
507
508    /// Use the given image as a writable depth/stencil attachment in a renderpass
509    pub fn modify_depth_stencil_attachment(
510        &mut self,
511        node: RenderGraphNodeId,
512        image: RenderGraphImageUsageId,
513        clear_depth_stencil_value: Option<RafxDepthStencilClearValue>,
514        mut constraint: RenderGraphImageConstraint,
515        view_options: RenderGraphImageViewOptions,
516    ) -> RenderGraphImageUsageId {
517        constraint.resource_type |= RafxResourceType::RENDER_TARGET_DEPTH_STENCIL;
518
519        // Add the read to the graph
520        let (read_image, write_image) =
521            self.add_image_modify(node, image, constraint, view_options);
522
523        self.set_depth_attachment(
524            node,
525            RenderGraphPassDepthAttachmentInfo {
526                attachment_type: RenderGraphPassAttachmentType::Modify,
527                clear_depth_stencil_value,
528                read_image: Some(read_image),
529                write_image: Some(write_image),
530                has_depth: true,
531                has_stencil: true,
532            },
533        );
534
535        write_image
536    }
537
538    /// Use the given image as a shader resource (i.e. can sample from the image) in a renderpass
539    pub fn sample_image(
540        &mut self,
541        node: RenderGraphNodeId,
542        image: RenderGraphImageUsageId,
543        mut constraint: RenderGraphImageConstraint,
544        view_options: RenderGraphImageViewOptions,
545    ) -> RenderGraphImageUsageId {
546        constraint.resource_type |= RafxResourceType::TEXTURE;
547
548        // Add the read to the graph
549        let usage = self.add_image_read(node, image, constraint, view_options);
550
551        self.node_mut(node).sampled_images.push(usage);
552        usage
553    }
554
555    //NOTE: While the buffer aspect flags may seem redundant with subresource_range here, the
556    // subresource_range should indicate the buffer view's supported aspects and the provided
557    // buffer aspect flags the aspects that are actually being used
558    pub(super) fn add_buffer_usage(
559        &mut self,
560        user: RenderGraphBufferUser,
561        version: RenderGraphBufferVersionId,
562        usage_type: RenderGraphBufferUsageType,
563    ) -> RenderGraphBufferUsageId {
564        let usage_id = RenderGraphBufferUsageId(self.buffer_usages.len());
565        self.buffer_usages.push(RenderGraphBufferUsage {
566            user,
567            usage_type,
568            version,
569        });
570        usage_id
571    }
572
573    // Add a buffer that can be used by nodes
574    pub(super) fn add_buffer_create(
575        &mut self,
576        create_node: RenderGraphNodeId,
577        constraint: RenderGraphBufferConstraint,
578    ) -> RenderGraphBufferUsageId {
579        let version_id = RenderGraphBufferVersionId {
580            index: self.buffer_resources.len(),
581            version: 0,
582        };
583        let usage_id = self.add_buffer_usage(
584            RenderGraphBufferUser::Node(create_node),
585            version_id,
586            RenderGraphBufferUsageType::Create,
587        );
588
589        let mut resource = RenderGraphBufferResource::new();
590
591        let version_info = RenderGraphBufferResourceVersionInfo::new(create_node, usage_id);
592        resource.versions.push(version_info);
593
594        // Add it to the graph
595        self.buffer_resources.push(resource);
596
597        self.nodes[create_node.0]
598            .buffer_creates
599            .push(RenderGraphBufferCreate {
600                buffer: usage_id,
601                constraint,
602            });
603
604        usage_id
605    }
606
607    pub(super) fn add_buffer_read(
608        &mut self,
609        read_node: RenderGraphNodeId,
610        buffer: RenderGraphBufferUsageId,
611        constraint: RenderGraphBufferConstraint,
612    ) -> RenderGraphBufferUsageId {
613        let version_id = self.buffer_usage(buffer).version;
614
615        let usage_id = self.add_buffer_usage(
616            RenderGraphBufferUser::Node(read_node),
617            version_id,
618            RenderGraphBufferUsageType::Read,
619        );
620
621        self.buffer_resources[version_id.index].versions[version_id.version]
622            .add_read_usage(usage_id);
623
624        self.nodes[read_node.0]
625            .buffer_reads
626            .push(RenderGraphBufferRead {
627                buffer: usage_id,
628                constraint,
629            });
630
631        usage_id
632    }
633
634    pub(super) fn add_buffer_modify(
635        &mut self,
636        modify_node: RenderGraphNodeId,
637        buffer: RenderGraphBufferUsageId,
638        constraint: RenderGraphBufferConstraint,
639    ) -> (RenderGraphBufferUsageId, RenderGraphBufferUsageId) {
640        let read_version_id = self.buffer_usage(buffer).version;
641
642        let read_usage_id = self.add_buffer_usage(
643            RenderGraphBufferUser::Node(modify_node),
644            read_version_id,
645            RenderGraphBufferUsageType::ModifyRead,
646        );
647
648        self.buffer_resources[read_version_id.index].versions[read_version_id.version]
649            .add_read_usage(read_usage_id);
650
651        // Create a new version and add it to the buffer
652        let version = self.buffer_resources[read_version_id.index].versions.len();
653        let write_version_id = RenderGraphBufferVersionId {
654            index: read_version_id.index,
655            version,
656        };
657        let write_usage_id = self.add_buffer_usage(
658            RenderGraphBufferUser::Node(modify_node),
659            write_version_id,
660            RenderGraphBufferUsageType::ModifyWrite,
661        );
662
663        let version_info = RenderGraphBufferResourceVersionInfo::new(modify_node, write_usage_id);
664        self.buffer_resources[read_version_id.index]
665            .versions
666            .push(version_info);
667
668        self.nodes[modify_node.0]
669            .buffer_modifies
670            .push(RenderGraphBufferModify {
671                input: read_usage_id,
672                output: write_usage_id,
673                constraint,
674            });
675
676        (read_usage_id, write_usage_id)
677    }
678
679    /// Use the given buffer as a vertex buffer
680    pub fn read_vertex_buffer(
681        &mut self,
682        node: RenderGraphNodeId,
683        buffer: RenderGraphBufferUsageId,
684        mut constraint: RenderGraphBufferConstraint,
685    ) -> RenderGraphBufferUsageId {
686        assert_eq!(self.node(node).kind, RenderGraphNodeKind::Renderpass);
687        constraint.resource_type |= RafxResourceType::VERTEX_BUFFER;
688
689        let usage = self.add_buffer_read(node, buffer, constraint);
690        self.node_mut(node).vertex_buffer_reads.push(buffer);
691        usage
692    }
693
694    /// Use the given buffer as an index buffer
695    pub fn read_index_buffer(
696        &mut self,
697        node: RenderGraphNodeId,
698        buffer: RenderGraphBufferUsageId,
699        mut constraint: RenderGraphBufferConstraint,
700    ) -> RenderGraphBufferUsageId {
701        assert_eq!(self.node(node).kind, RenderGraphNodeKind::Renderpass);
702        constraint.resource_type |= RafxResourceType::INDEX_BUFFER;
703
704        let usage = self.add_buffer_read(node, buffer, constraint);
705        self.node_mut(node).index_buffer_reads.push(buffer);
706        usage
707    }
708
709    /// Use the given buffer as an indirect buffer
710    pub fn read_indirect_buffer(
711        &mut self,
712        node: RenderGraphNodeId,
713        buffer: RenderGraphBufferUsageId,
714        mut constraint: RenderGraphBufferConstraint,
715    ) -> RenderGraphBufferUsageId {
716        constraint.resource_type |= RafxResourceType::INDIRECT_BUFFER;
717
718        let usage = self.add_buffer_read(node, buffer, constraint);
719        self.node_mut(node).indirect_buffer_reads.push(buffer);
720        usage
721    }
722
723    /// Use the given buffer as a uniform buffer
724    pub fn read_uniform_buffer(
725        &mut self,
726        node: RenderGraphNodeId,
727        buffer: RenderGraphBufferUsageId,
728        mut constraint: RenderGraphBufferConstraint,
729    ) -> RenderGraphBufferUsageId {
730        constraint.resource_type |= RafxResourceType::UNIFORM_BUFFER;
731
732        //TODO: In the future could consider options for determining stage flags to be compute or
733        // fragment. Check node queue? Check if attachments exist? Explicit?
734        let usage = self.add_buffer_read(node, buffer, constraint);
735        self.node_mut(node).uniform_buffer_reads.push(buffer);
736        usage
737    }
738
739    /// Use the given buffer as a copy source
740    pub fn read_copy_src_buffer(
741        &mut self,
742        node: RenderGraphNodeId,
743        buffer: RenderGraphBufferUsageId,
744        constraint: RenderGraphBufferConstraint,
745    ) -> RenderGraphBufferUsageId {
746        let usage = self.add_buffer_read(node, buffer, constraint);
747        self.node_mut(node).copy_src_buffer_reads.push(buffer);
748        usage
749    }
750
751    /// Use the given buffer as a copy destination
752    pub fn write_copy_dst_buffer(
753        &mut self,
754        node: RenderGraphNodeId,
755        buffer: RenderGraphBufferUsageId,
756        constraint: RenderGraphBufferConstraint,
757    ) -> RenderGraphBufferUsageId {
758        //NOTE: Be careful modifying this.. double check if any changes here copy_buffer_to_buffer()
759        // need to be applied to the None dst_buffer codepath
760        let (read_buffer, write_buffer) = self.add_buffer_modify(node, buffer, constraint);
761        self.node_mut(node).copy_dst_buffer_writes.push(read_buffer);
762        write_buffer
763    }
764
765    /// Use the given image as a copy source
766    pub fn read_copy_src_image(
767        &mut self,
768        node: RenderGraphNodeId,
769        image: RenderGraphImageUsageId,
770        constraint: RenderGraphImageConstraint,
771        view_options: RenderGraphImageViewOptions,
772    ) -> RenderGraphImageUsageId {
773        let usage = self.add_image_read(node, image, constraint, view_options);
774        self.node_mut(node).copy_src_image_reads.push(image);
775        usage
776    }
777
778    /// Use the given image as a copy destination
779    pub fn write_copy_dst_image(
780        &mut self,
781        node: RenderGraphNodeId,
782        image: RenderGraphImageUsageId,
783        constraint: RenderGraphImageConstraint,
784        view_options: RenderGraphImageViewOptions,
785    ) -> RenderGraphImageUsageId {
786        let (read_image, write_image) =
787            self.add_image_modify(node, image, constraint, view_options);
788        self.node_mut(node).copy_dst_image_writes.push(read_image);
789        write_image
790    }
791
792    // Utility function for create_storage_buffer() and modify_storage_buffer() to setup a clear
793    fn setup_buffer_clear_callback(
794        &mut self,
795        node: RenderGraphNodeId,
796        buffer: RenderGraphBufferUsageId,
797    ) {
798        self.set_callback(node, move |args| {
799            let buffer = args.graph_context.buffer(buffer).unwrap();
800            let builtin_pipelines = args.graph_context.resource_context().builtin_pipelines();
801            builtin_pipelines.fill_buffer(
802                &*args.command_buffer,
803                args.graph_context.resource_context(),
804                &buffer,
805                0,
806            )
807        });
808    }
809
810    /// Create a storage buffer and use it as a writable shader resource
811    pub fn create_storage_buffer(
812        &mut self,
813        node: RenderGraphNodeId,
814        mut constraint: RenderGraphBufferConstraint,
815        load_op: RafxLoadOp,
816    ) -> RenderGraphBufferUsageId {
817        constraint.resource_type |= RafxResourceType::BUFFER_READ_WRITE;
818
819        match load_op {
820            RafxLoadOp::DontCare => {
821                let usage = self.add_buffer_create(node, constraint);
822                self.node_mut(node).storage_buffer_creates.push(usage);
823                usage
824            }
825            RafxLoadOp::Load => unimplemented!("RafxLoadOp::Load not supported in create_storage_buffer call. Use modify_storage_image instead."),
826            RafxLoadOp::Clear => {
827                // Add a node to clear the buffer
828                let clear_node = self.add_callback_node("create_storage_buffer_clear", self.node(node).queue);
829                let cleared_buffer = self.add_buffer_create(clear_node, constraint);
830                self.node_mut(clear_node).storage_buffer_creates.push(cleared_buffer);
831                self.setup_buffer_clear_callback(clear_node, cleared_buffer);
832
833                // Now set this node up to modify the buffer
834                let (read_usage, write_usage) = self.add_buffer_modify(node, cleared_buffer, Default::default());
835                self.node_mut(node).storage_buffer_modifies.push(read_usage);
836                write_usage
837            }
838        }
839    }
840
841    /// Use the given storage buffer as a read-only shader resource
842    pub fn read_storage_buffer(
843        &mut self,
844        node: RenderGraphNodeId,
845        buffer: RenderGraphBufferUsageId,
846        mut constraint: RenderGraphBufferConstraint,
847        // load_op is assumed to be Load, otherwise use create_storage_image
848    ) -> RenderGraphBufferUsageId {
849        constraint.resource_type |= RafxResourceType::BUFFER_READ_WRITE;
850
851        //TODO: In the future could consider options for determining stage flags to be compute or
852        // fragment. Check node queue? Check if attachments exist? Explicit?
853        let usage = self.add_buffer_read(node, buffer, constraint);
854        self.node_mut(node).storage_buffer_reads.push(usage);
855        usage
856    }
857
858    /// Use the given storage buffer as a writable shader resource
859    pub fn modify_storage_buffer(
860        &mut self,
861        node: RenderGraphNodeId,
862        buffer: RenderGraphBufferUsageId,
863        mut constraint: RenderGraphBufferConstraint,
864        load_op: RafxLoadOp,
865    ) -> RenderGraphBufferUsageId {
866        constraint.resource_type |= RafxResourceType::BUFFER_READ_WRITE;
867
868        match load_op {
869            // Don't clear the buffer
870            RafxLoadOp::DontCare | RafxLoadOp::Load => {
871                let (read_buffer, write_buffer) = self.add_buffer_modify(node, buffer, constraint);
872                self.node_mut(node)
873                    .storage_buffer_modifies
874                    .push(read_buffer);
875                write_buffer
876            }
877            RafxLoadOp::Clear => {
878                // Add a node to clear the buffer
879                let clear_node =
880                    self.add_callback_node("modify_storage_buffer_clear", self.node(node).queue);
881                let (cleared_buffer_read, cleared_buffer_write) =
882                    self.add_buffer_modify(clear_node, buffer, constraint);
883                self.node_mut(clear_node)
884                    .storage_buffer_modifies
885                    .push(cleared_buffer_read);
886                self.setup_buffer_clear_callback(clear_node, cleared_buffer_write);
887
888                let (read_usage, write_usage) =
889                    self.add_buffer_modify(node, cleared_buffer_write, Default::default());
890                self.node_mut(node).storage_buffer_modifies.push(read_usage);
891                write_usage
892            }
893        }
894    }
895
896    //NOTE: Image will not be cleared, use clear_image_before_pass() on the returned value if it needs to be
897    // initialized to zero
898    /// Create a storage image and use it as a writable shader resource
899    pub fn create_storage_image(
900        &mut self,
901        node: RenderGraphNodeId,
902        mut constraint: RenderGraphImageConstraint,
903        view_options: RenderGraphImageViewOptions,
904    ) -> RenderGraphImageUsageId {
905        constraint.resource_type |= RafxResourceType::TEXTURE_READ_WRITE;
906
907        //TODO: In the future could consider options for determining stage flags to be compute or
908        // fragment. Check node queue? Check if attachments exist? Explicit?
909        let usage = self.add_image_create(node, constraint, view_options);
910        self.node_mut(node).storage_image_creates.push(usage);
911        usage
912    }
913
914    /// Use the given storage image as a read-only shader resource
915    pub fn read_storage_image(
916        &mut self,
917        node: RenderGraphNodeId,
918        image: RenderGraphImageUsageId,
919        mut constraint: RenderGraphImageConstraint,
920        view_options: RenderGraphImageViewOptions,
921        // load_op is assumed to be Load, otherwise use create_storage_image
922    ) -> RenderGraphImageUsageId {
923        constraint.resource_type |= RafxResourceType::TEXTURE_READ_WRITE;
924
925        //TODO: In the future could consider options for determining stage flags to be compute or
926        // fragment. Check node queue? Check if attachments exist? Explicit?
927        let usage = self.add_image_read(node, image, constraint, view_options);
928        self.node_mut(node).storage_image_reads.push(usage);
929
930        usage
931    }
932
933    /// Use the given storage image as a writable shader resource
934    pub fn modify_storage_image(
935        &mut self,
936        node: RenderGraphNodeId,
937        image: RenderGraphImageUsageId,
938        mut constraint: RenderGraphImageConstraint,
939        view_options: RenderGraphImageViewOptions,
940    ) -> RenderGraphImageUsageId {
941        constraint.resource_type |= RafxResourceType::TEXTURE_READ_WRITE;
942
943        //TODO: In the future could consider options for determining stage flags to be compute or
944        // fragment. Check node queue? Check if attachments exist? Explicit?
945        let (read_image, write_image) =
946            self.add_image_modify(node, image, constraint, view_options);
947
948        self.node_mut(node).storage_image_modifies.push(read_image);
949        write_image
950    }
951
952    /// Register a non-rendergraph image for use with the rendergraph. (Use read_external_image() or
953    /// write_external_image() to access it)
954    pub fn add_external_image(
955        &mut self,
956        image_resource: ResourceArc<ImageViewResource>,
957        view_options: RenderGraphImageViewOptions,
958        #[allow(unused_mut)] mut initial_state: RafxResourceState,
959        final_state: RafxResourceState,
960    ) -> RenderGraphExternalImageId {
961        let image_view = image_resource.get_raw().image;
962        let image = image_view.get_raw().image;
963
964        // A vulkan-specific check - images may have started in an undefined layout. Normally this
965        // is handled by transitioning the resource into the correct state, and there is logic in
966        // the vulkan backend to assume the first transition is from UNDEFINED state. However if we
967        // indicate the "normal" initial state for the frame, we might not even try to do a layout
968        // transition and we will skip that code in the backend.
969        #[cfg(feature = "rafx-vulkan")]
970        {
971            if let Some(vk_texture) = image.vk_texture() {
972                if vk_texture.is_in_initial_undefined_layout() {
973                    initial_state = RafxResourceState::UNDEFINED
974                }
975            }
976        }
977
978        let texture_def = image.texture_def();
979        let specification = RenderGraphImageSpecification {
980            resource_type: texture_def.resource_type,
981            format: texture_def.format,
982            extents: texture_def.extents,
983            mip_count: texture_def.mip_count,
984            layer_count: texture_def.array_length,
985            samples: texture_def.sample_count,
986        };
987
988        let external_image_id = RenderGraphExternalImageId(self.external_images.len());
989
990        // Add it to the graph
991        let image_resource_index = self.image_resources.len();
992        self.image_resources.push(RenderGraphImageResource::new());
993
994        let external_image = RenderGraphExternalImage {
995            external_image_id,
996            specification,
997            view_options,
998            image_resource,
999            image_resource_index,
1000            input_usage: None,
1001            output_usage: None,
1002            initial_state,
1003            final_state,
1004        };
1005
1006        self.external_images.push(external_image);
1007        external_image_id
1008    }
1009
1010    /// Register a non-rendergraph buffer for use with the rendergraph. (Use read_external_buffer() or
1011    /// write_external_buffer() to access it)
1012    pub fn add_external_buffer(
1013        &mut self,
1014        buffer_resource: ResourceArc<BufferResource>,
1015        initial_state: RafxResourceState,
1016        final_state: RafxResourceState,
1017    ) -> RenderGraphExternalBufferId {
1018        let buffer = buffer_resource.get_raw().buffer;
1019        let buffer_def = buffer.buffer_def();
1020        let specification = RenderGraphBufferSpecification {
1021            size: buffer_def.size,
1022            resource_type: buffer_def.resource_type,
1023        };
1024
1025        let external_buffer_id = RenderGraphExternalBufferId(self.external_buffers.len());
1026
1027        let buffer_resource_index = self.buffer_resources.len();
1028        self.buffer_resources.push(RenderGraphBufferResource::new());
1029
1030        let external_buffer = RenderGraphExternalBuffer {
1031            external_buffer_id,
1032            specification,
1033            buffer_resource,
1034            buffer_resource_index,
1035            input_usage: None,
1036            output_usage: None,
1037            initial_state,
1038            final_state,
1039        };
1040
1041        self.external_buffers.push(external_buffer);
1042        external_buffer_id
1043    }
1044
1045    /// Use an external image as an input for a render graph node
1046    pub fn read_external_image(
1047        &mut self,
1048        external_image_id: RenderGraphExternalImageId,
1049    ) -> RenderGraphImageUsageId {
1050        let external_image = &self.external_images[external_image_id.0];
1051        let image_resource_index = external_image.image_resource_index;
1052        let view_options = external_image.view_options.clone();
1053
1054        let version_id = RenderGraphImageVersionId {
1055            index: image_resource_index,
1056            version: 0,
1057        };
1058
1059        let input_usage = self.add_image_usage(
1060            RenderGraphImageUser::Input(external_image_id),
1061            version_id,
1062            RenderGraphImageUsageType::Input,
1063            view_options,
1064        );
1065
1066        let version_info =
1067            RenderGraphImageResourceVersionInfo::new(RenderGraphNodeId(0), input_usage);
1068        let resource = &mut self.image_resources[image_resource_index];
1069        resource.versions.push(version_info);
1070
1071        self.external_images[external_image_id.0].input_usage = Some(input_usage);
1072        input_usage
1073    }
1074
1075    /// Use an external buffer as an input for a render graph node
1076    pub fn read_external_buffer(
1077        &mut self,
1078        external_buffer_id: RenderGraphExternalBufferId,
1079    ) -> RenderGraphBufferUsageId {
1080        let external_buffer = &self.external_buffers[external_buffer_id.0];
1081        let buffer_resource_index = external_buffer.buffer_resource_index;
1082
1083        let version_id = RenderGraphBufferVersionId {
1084            index: buffer_resource_index,
1085            version: 0,
1086        };
1087
1088        let input_usage = self.add_buffer_usage(
1089            RenderGraphBufferUser::Input(external_buffer_id),
1090            version_id,
1091            RenderGraphBufferUsageType::Input,
1092        );
1093
1094        let version_info =
1095            RenderGraphBufferResourceVersionInfo::new(RenderGraphNodeId(0), input_usage);
1096        let resource = &mut self.buffer_resources[buffer_resource_index];
1097        resource.versions.push(version_info);
1098
1099        self.external_buffers[external_buffer_id.0].input_usage = Some(input_usage);
1100        input_usage
1101    }
1102
1103    /// Use an external image as an output for a render graph node
1104    pub fn write_external_image(
1105        &mut self,
1106        external_image_id: RenderGraphExternalImageId,
1107        image_id: RenderGraphImageUsageId,
1108    ) {
1109        let external_image = &self.external_images[external_image_id.0];
1110        let view_options = external_image.view_options.clone();
1111
1112        let version_id = self.image_version_id(image_id);
1113        let usage_id = self.add_image_usage(
1114            RenderGraphImageUser::Output(external_image_id),
1115            version_id,
1116            RenderGraphImageUsageType::Output,
1117            view_options,
1118        );
1119
1120        let image_version = self.image_version_info_mut(image_id);
1121        image_version.read_usages.push(usage_id);
1122
1123        self.external_images[external_image_id.0].output_usage = Some(usage_id);
1124    }
1125
1126    /// Use an external buffer as an output for a render graph node
1127    pub fn write_external_buffer(
1128        &mut self,
1129        external_buffer_id: RenderGraphExternalBufferId,
1130        buffer_id: RenderGraphBufferUsageId,
1131    ) {
1132        let version_id = self.buffer_version_id(buffer_id);
1133        let usage_id = self.add_buffer_usage(
1134            RenderGraphBufferUser::Output(external_buffer_id),
1135            version_id,
1136            RenderGraphBufferUsageType::Output,
1137        );
1138
1139        let buffer_version = self.buffer_version_info_mut(buffer_id);
1140        buffer_version.read_usages.push(usage_id);
1141
1142        self.external_buffers[external_buffer_id.0].output_usage = Some(usage_id);
1143    }
1144
1145    /// Schedule a GPU copy from one buffer to another. If dst_buffer is None, create a copy of the
1146    /// src_buffer.
1147    pub fn copy_buffer_to_buffer(
1148        &mut self,
1149        name: RenderGraphNodeName,
1150        queue: RenderGraphQueue,
1151        src_buffer: RenderGraphBufferUsageId,
1152        dst_buffer: Option<RenderGraphBufferUsageId>,
1153        params: Option<RafxCmdCopyBufferToBufferParams>,
1154    ) -> RenderGraphBufferUsageId {
1155        let node = self.add_callback_node(name, queue);
1156        let src_buffer = self.read_copy_src_buffer(node, src_buffer, Default::default());
1157        let dst_buffer = if let Some(dst_buffer) = dst_buffer {
1158            self.write_copy_dst_buffer(node, dst_buffer, Default::default())
1159        } else {
1160            // This is a combination of create_storage_buffer() and write_copy_dst_buffer()
1161            let dst_buffer = self.add_buffer_create(node, Default::default());
1162            self.node_mut(node).copy_dst_buffer_writes.push(dst_buffer);
1163            dst_buffer
1164        };
1165
1166        self.nodes[node.0]
1167            .buffer_copies
1168            .push(RenderGraphBufferCopy {
1169                input: src_buffer,
1170                output: dst_buffer,
1171                constraint: Default::default(),
1172            });
1173
1174        self.set_callback(node, move |args| {
1175            let src = args.graph_context.buffer(src_buffer).unwrap();
1176            let dst = args.graph_context.buffer(dst_buffer).unwrap();
1177
1178            let params = params.clone().unwrap_or_else(|| {
1179                let src_size = src.get_raw().buffer.buffer_def().size;
1180                let dst_size = dst.get_raw().buffer.buffer_def().size;
1181                assert_eq!(src_size, dst_size);
1182
1183                RafxCmdCopyBufferToBufferParams {
1184                    src_byte_offset: 0,
1185                    dst_byte_offset: 0,
1186                    size: src_size,
1187                }
1188            });
1189
1190            args.command_buffer.cmd_copy_buffer_to_buffer(
1191                &src.get_raw().buffer,
1192                &dst.get_raw().buffer,
1193                &params,
1194            )
1195        });
1196
1197        dst_buffer
1198    }
1199
1200    /// Create a buffer and schedule a GPU copy from the src_buffer into it. (Shorthand for using
1201    /// copy_buffer_to_buffer())
1202    pub fn clone_buffer(
1203        &mut self,
1204        name: RenderGraphNodeName,
1205        queue: RenderGraphQueue,
1206        src_buffer: RenderGraphBufferUsageId,
1207        params: Option<RafxCmdCopyBufferToBufferParams>,
1208    ) -> RenderGraphBufferUsageId {
1209        self.copy_buffer_to_buffer(name, queue, src_buffer, None, params)
1210    }
1211
1212    /// Schedule a GPU copy from one image to another. If dst_image is None, create a copy of the
1213    /// src_image.
1214    pub fn copy_image_to_image(
1215        &mut self,
1216        name: RenderGraphNodeName,
1217        queue: RenderGraphQueue,
1218        src_image: RenderGraphImageUsageId,
1219        dst_image: Option<RenderGraphImageUsageId>,
1220        params: Option<RafxCmdCopyTextureToTextureParams>,
1221    ) -> RenderGraphImageUsageId {
1222        let node = self.add_callback_node(name, queue);
1223
1224        let array_slices = params.as_ref().map(|x| x.array_slices).flatten();
1225        let src_image = self.read_copy_src_image(
1226            node,
1227            src_image,
1228            Default::default(),
1229            RenderGraphImageViewOptions {
1230                texture_bind_type: None,
1231                array_slice: array_slices.map(|x| x[0]),
1232                mip_slice: Some(params.as_ref().map(|x| x.src_mip_level).unwrap_or(0)),
1233            },
1234        );
1235
1236        let dst_image_view_options = RenderGraphImageViewOptions {
1237            texture_bind_type: None,
1238            array_slice: array_slices.map(|x| x[1]),
1239            mip_slice: Some(params.as_ref().map(|x| x.dst_mip_level).unwrap_or(0)),
1240        };
1241
1242        let dst_image = if let Some(dst_image) = dst_image {
1243            self.write_copy_dst_image(node, dst_image, Default::default(), dst_image_view_options)
1244        } else {
1245            // This is a combination of create_storage_image() and write_copy_dst_image()
1246            let dst_image = self.add_image_create(node, Default::default(), dst_image_view_options);
1247            self.node_mut(node).copy_dst_image_writes.push(dst_image);
1248            dst_image
1249        };
1250
1251        self.nodes[node.0].image_copies.push(RenderGraphImageCopy {
1252            input: src_image,
1253            output: dst_image,
1254            constraint: Default::default(),
1255        });
1256
1257        self.set_callback(node, move |args| {
1258            let src = args.graph_context.image_view(src_image).unwrap();
1259            let dst = args.graph_context.image_view(dst_image).unwrap();
1260
1261            let params = params.clone().unwrap_or_else(|| {
1262                let src_size = src.get_raw().image.get_raw().image.texture_def().extents;
1263                let dst_size = dst.get_raw().image.get_raw().image.texture_def().extents;
1264                assert_eq!(src_size, dst_size);
1265
1266                RafxCmdCopyTextureToTextureParams {
1267                    src_offset: Default::default(),
1268                    dst_offset: Default::default(),
1269                    extents: src_size,
1270                    src_mip_level: 0,
1271                    dst_mip_level: 0,
1272                    array_slices: None,
1273                }
1274            });
1275
1276            args.command_buffer.cmd_copy_texture_to_texture(
1277                &src.get_raw().image.get_raw().image,
1278                &dst.get_raw().image.get_raw().image,
1279                &params,
1280            )?;
1281            Ok(())
1282        });
1283
1284        dst_image
1285    }
1286
1287    /// Create a image and schedule a GPU copy from the src_buffer into it. (Shorthand for using
1288    /// copy_image_to_image())
1289    pub fn clone_image(
1290        &mut self,
1291        name: RenderGraphNodeName,
1292        queue: RenderGraphQueue,
1293        src_image: RenderGraphImageUsageId,
1294        params: Option<RafxCmdCopyTextureToTextureParams>,
1295    ) -> RenderGraphImageUsageId {
1296        self.copy_image_to_image(name, queue, src_image, None, params)
1297    }
1298
1299    /// Render the src_image into the dst_image. This is less efficient than copy_image_to_image,
1300    /// but is more flexible. (It is essentially drawing the src_image as a quad on the dst_image)
1301    pub fn blit_image_to_image(
1302        &mut self,
1303        name: RenderGraphNodeName,
1304        queue: RenderGraphQueue,
1305        src_image: RenderGraphImageUsageId,
1306        src_min_uv: glam::Vec2,
1307        src_max_uv: glam::Vec2,
1308        dst_image: RenderGraphImageUsageId,
1309        dst_min_uv: glam::Vec2,
1310        dst_max_uv: glam::Vec2,
1311    ) -> RenderGraphImageUsageId {
1312        let node = self.add_renderpass_node(name, queue);
1313        let src_image = self.sample_image(node, src_image, Default::default(), Default::default());
1314        let dst_image = self.modify_color_attachment(
1315            node,
1316            dst_image,
1317            0,
1318            None,
1319            Default::default(),
1320            Default::default(),
1321        );
1322
1323        self.set_renderpass_callback(node, move |args| {
1324            let src_image = args.graph_context.image_view(src_image).unwrap();
1325            let dst_image = args.graph_context.image_view(dst_image).unwrap();
1326            let builtin_pipelines = args.graph_context.resource_context().builtin_pipelines();
1327
1328            builtin_pipelines.blit_image(
1329                &*args.command_buffer,
1330                args.graph_context.resource_context(),
1331                &args.render_target_meta,
1332                &src_image,
1333                src_min_uv,
1334                src_max_uv,
1335                &dst_image,
1336                dst_min_uv,
1337                dst_max_uv,
1338            )
1339        });
1340
1341        dst_image
1342    }
1343
1344    pub fn add_renderpass_node(
1345        &mut self,
1346        name: RenderGraphNodeName,
1347        queue: RenderGraphQueue,
1348    ) -> RenderGraphNodeId {
1349        self.add_node(name, RenderGraphNodeKind::Renderpass, queue)
1350    }
1351
1352    pub fn add_callback_node(
1353        &mut self,
1354        name: RenderGraphNodeName,
1355        queue: RenderGraphQueue,
1356    ) -> RenderGraphNodeId {
1357        self.add_node(name, RenderGraphNodeKind::Callback, queue)
1358    }
1359
1360    // Add a node which can use resources
1361    pub fn add_node(
1362        &mut self,
1363        name: RenderGraphNodeName,
1364        kind: RenderGraphNodeKind,
1365        queue: RenderGraphQueue,
1366    ) -> RenderGraphNodeId {
1367        let node = RenderGraphNodeId(self.nodes.len());
1368        self.nodes
1369            .push(RenderGraphNode::new(node, Some(name), kind, queue));
1370        node
1371    }
1372
1373    pub fn add_node_unnamed(
1374        &mut self,
1375        kind: RenderGraphNodeKind,
1376        queue: RenderGraphQueue,
1377    ) -> RenderGraphNodeId {
1378        let node = RenderGraphNodeId(self.nodes.len());
1379        self.nodes
1380            .push(RenderGraphNode::new(node, None, kind, queue));
1381        node
1382    }
1383
1384    pub fn set_node_required(
1385        &mut self,
1386        node_id: RenderGraphNodeId,
1387    ) {
1388        self.node_mut(node_id).can_be_culled = false;
1389    }
1390
1391    pub fn add_explicit_dependency(
1392        &mut self,
1393        before_node_id: RenderGraphNodeId,
1394        after_node_id: RenderGraphNodeId,
1395    ) {
1396        self.node_mut(after_node_id)
1397            .explicit_dependencies
1398            .push(before_node_id);
1399    }
1400
1401    pub fn set_buffer_required(
1402        &mut self,
1403        buffer_usage: RenderGraphBufferUsageId,
1404    ) {
1405        let creator_node = self.buffer_version_info(buffer_usage).creator_node;
1406        self.set_node_required(creator_node);
1407    }
1408
1409    pub fn set_image_required(
1410        &mut self,
1411        image_usage: RenderGraphImageUsageId,
1412    ) {
1413        let creator_node = self.image_version_info(image_usage).creator_node;
1414        self.set_node_required(creator_node);
1415    }
1416
1417    pub fn set_node_name(
1418        &mut self,
1419        node_id: RenderGraphNodeId,
1420        name: RenderGraphNodeName,
1421    ) {
1422        self.node_mut(node_id).name = Some(name);
1423    }
1424
1425    pub fn set_image_name(
1426        &mut self,
1427        image_id: RenderGraphImageUsageId,
1428        name: RenderGraphResourceName,
1429    ) {
1430        self.image_resource_mut(image_id).name = Some(name);
1431    }
1432
1433    pub fn set_buffer_name(
1434        &mut self,
1435        buffer_id: RenderGraphBufferUsageId,
1436        name: RenderGraphResourceName,
1437    ) {
1438        self.buffer_resource_mut(buffer_id).name = Some(name);
1439    }
1440
1441    //
1442    // Callbacks
1443    //
1444
1445    /// Adds a callback that receives the renderpass associated with the node
1446    pub fn set_renderpass_callback<CallbackFnT>(
1447        &mut self,
1448        node_id: RenderGraphNodeId,
1449        f: CallbackFnT,
1450    ) where
1451        CallbackFnT: Fn(VisitRenderpassNodeArgs) -> RafxResult<()> + 'static + Send,
1452    {
1453        assert_eq!(self.node(node_id).kind, RenderGraphNodeKind::Renderpass);
1454        let old = self.visit_node_callbacks.insert(
1455            node_id,
1456            RenderGraphNodeVisitNodeCallback::Render(Box::new(f)),
1457        );
1458        // If this trips, multiple callbacks were set on the node
1459        assert!(old.is_none());
1460    }
1461
1462    /// Adds a callback for compute based nodes
1463    pub fn set_callback<CallbackFnT>(
1464        &mut self,
1465        node_id: RenderGraphNodeId,
1466        f: CallbackFnT,
1467    ) where
1468        CallbackFnT: Fn(VisitComputeNodeArgs) -> RafxResult<()> + 'static + Send,
1469    {
1470        assert_eq!(self.node(node_id).kind, RenderGraphNodeKind::Callback);
1471        let old = self.visit_node_callbacks.insert(
1472            node_id,
1473            RenderGraphNodeVisitNodeCallback::Callback(Box::new(f)),
1474        );
1475        // If this trips, multiple callbacks were set on the node
1476        assert!(old.is_none());
1477    }
1478
1479    pub fn add_render_phase_dependency<PhaseT: RenderPhase>(
1480        &mut self,
1481        node_id: RenderGraphNodeId,
1482    ) {
1483        self.render_phase_dependencies
1484            .entry(node_id)
1485            .or_default()
1486            .insert(PhaseT::render_phase_index());
1487    }
1488
1489    //
1490    // Get nodes
1491    //
1492    pub(super) fn node(
1493        &self,
1494        node_id: RenderGraphNodeId,
1495    ) -> &RenderGraphNode {
1496        &self.nodes[node_id.0]
1497    }
1498
1499    pub(super) fn node_mut(
1500        &mut self,
1501        node_id: RenderGraphNodeId,
1502    ) -> &mut RenderGraphNode {
1503        &mut self.nodes[node_id.0]
1504    }
1505
1506    //
1507    // Get images
1508    //
1509    pub(super) fn image_resource(
1510        &self,
1511        usage_id: RenderGraphImageUsageId,
1512    ) -> &RenderGraphImageResource {
1513        let version = self.image_usages[usage_id.0].version;
1514        &self.image_resources[version.index]
1515    }
1516
1517    pub(super) fn image_resource_mut(
1518        &mut self,
1519        usage_id: RenderGraphImageUsageId,
1520    ) -> &mut RenderGraphImageResource {
1521        let version = self.image_usages[usage_id.0].version;
1522        &mut self.image_resources[version.index]
1523    }
1524
1525    //
1526    // Get image version infos
1527    //
1528    pub(super) fn image_usage(
1529        &self,
1530        usage_id: RenderGraphImageUsageId,
1531    ) -> &RenderGraphImageUsage {
1532        &self.image_usages[usage_id.0]
1533    }
1534
1535    pub(super) fn image_version_info(
1536        &self,
1537        usage_id: RenderGraphImageUsageId,
1538    ) -> &RenderGraphImageResourceVersionInfo {
1539        let version = self.image_usages[usage_id.0].version;
1540        &self.image_resources[version.index].versions[version.version]
1541    }
1542
1543    pub(super) fn image_version_info_mut(
1544        &mut self,
1545        usage_id: RenderGraphImageUsageId,
1546    ) -> &mut RenderGraphImageResourceVersionInfo {
1547        let version = self.image_usages[usage_id.0].version;
1548        &mut self.image_resources[version.index].versions[version.version]
1549    }
1550
1551    pub(super) fn image_version_id(
1552        &self,
1553        usage_id: RenderGraphImageUsageId,
1554    ) -> RenderGraphImageVersionId {
1555        self.image_usages[usage_id.0].version
1556    }
1557
1558    pub(super) fn image_version_create_usage(
1559        &self,
1560        usage: RenderGraphImageUsageId,
1561    ) -> RenderGraphImageUsageId {
1562        let version = self.image_usages[usage.0].version;
1563        self.image_resources[version.index].versions[version.version].create_usage
1564    }
1565
1566    pub(super) fn redirect_image_usage(
1567        &mut self,
1568        usage: RenderGraphImageUsageId,
1569        from: RenderGraphImageVersionId,
1570        to: RenderGraphImageVersionId,
1571    ) {
1572        self.image_resources[from.index].versions[from.version].remove_read_usage(usage);
1573        self.image_resources[to.index].versions[to.version].add_read_usage(usage);
1574    }
1575
1576    //
1577    // Get buffers
1578    //
1579    pub(super) fn buffer_resource(
1580        &self,
1581        usage_id: RenderGraphBufferUsageId,
1582    ) -> &RenderGraphBufferResource {
1583        let version = self.buffer_usage(usage_id).version;
1584        &self.buffer_resources[version.index]
1585    }
1586
1587    pub(super) fn buffer_resource_mut(
1588        &mut self,
1589        usage_id: RenderGraphBufferUsageId,
1590    ) -> &mut RenderGraphBufferResource {
1591        let version = self.buffer_usage(usage_id).version;
1592        &mut self.buffer_resources[version.index]
1593    }
1594
1595    //
1596    // Get buffer version infos
1597    //
1598    pub(super) fn buffer_usage(
1599        &self,
1600        usage_id: RenderGraphBufferUsageId,
1601    ) -> &RenderGraphBufferUsage {
1602        &self.buffer_usages[usage_id.0]
1603    }
1604
1605    pub(super) fn buffer_version_info(
1606        &self,
1607        usage_id: RenderGraphBufferUsageId,
1608    ) -> &RenderGraphBufferResourceVersionInfo {
1609        let version = self.buffer_usage(usage_id).version;
1610        &self.buffer_resources[version.index].versions[version.version]
1611    }
1612
1613    pub(super) fn buffer_version_info_mut(
1614        &mut self,
1615        usage_id: RenderGraphBufferUsageId,
1616    ) -> &mut RenderGraphBufferResourceVersionInfo {
1617        let version = self.buffer_usage(usage_id).version;
1618        &mut self.buffer_resources[version.index].versions[version.version]
1619    }
1620
1621    pub(super) fn buffer_version_id(
1622        &self,
1623        usage_id: RenderGraphBufferUsageId,
1624    ) -> RenderGraphBufferVersionId {
1625        self.buffer_usage(usage_id).version
1626    }
1627
1628    pub(super) fn buffer_version_create_usage(
1629        &self,
1630        usage: RenderGraphBufferUsageId,
1631    ) -> RenderGraphBufferUsageId {
1632        let version = self.buffer_usage(usage).version;
1633        self.buffer_resources[version.index].versions[version.version].create_usage
1634    }
1635
1636    //
1637    // Internal debug functions
1638    //
1639    pub(super) fn debug_user_name_of_image_usage(
1640        &self,
1641        usage: RenderGraphImageUsageId,
1642    ) -> String {
1643        let user = self.image_usage(usage).user;
1644        match user {
1645            RenderGraphImageUser::Node(node_id) => {
1646                format!("Node {:?} {:?}", node_id, self.node(node_id).name)
1647            }
1648            RenderGraphImageUser::Input(image_id) => format!("InputImage {:?}", image_id),
1649            RenderGraphImageUser::Output(image_id) => format!("OutputImage {:?}", image_id),
1650        }
1651    }
1652
1653    pub(super) fn debug_user_name_of_buffer_usage(
1654        &self,
1655        usage: RenderGraphBufferUsageId,
1656    ) -> String {
1657        let user = self.buffer_usage(usage).user;
1658        match user {
1659            RenderGraphBufferUser::Node(node_id) => {
1660                format!("Node {:?} {:?}", node_id, self.node(node_id).name)
1661            }
1662            RenderGraphBufferUser::Input(buffer_id) => format!("InputBuffer {:?}", buffer_id),
1663            RenderGraphBufferUser::Output(buffer_id) => format!("OutputBuffer {:?}", buffer_id),
1664        }
1665    }
1666
1667    pub fn build_plan(
1668        self,
1669        swapchain_surface_info: &SwapchainSurfaceInfo,
1670    ) -> RenderGraphPlan {
1671        profiling::scope!("Build Plan");
1672        RenderGraphPlan::new(self, swapchain_surface_info)
1673    }
1674}