rafx_framework/graph/
graph_buffer.rs

1use crate::graph::{RenderGraphNodeId, RenderGraphResourceName};
2use rafx_api::RafxResourceType;
3
4/// Unique ID for a particular usage (read or write) of a specific buffer
5#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
6pub struct RenderGraphBufferUsageId(pub(super) usize);
7
8/// An ID for a buffer used within the graph between passes
9#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
10pub struct VirtualBufferId(pub(super) usize);
11
12/// An ID for a buffer allocation (possibly reused)
13#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
14pub struct PhysicalBufferId(pub(super) usize);
15
16/// Unique ID provided for any buffer registered as an external buffer
17#[derive(Debug, Copy, Clone)]
18pub struct RenderGraphExternalBufferId(pub(super) usize);
19
20/// Unique ID for a particular version of a buffer. Any time a buffer is modified, a new version is
21/// produced
22#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
23pub struct RenderGraphBufferVersionId {
24    pub(super) index: usize,
25    pub(super) version: usize,
26}
27
28/// A "virtual" buffer that the render graph knows about. The render graph will allocate buffers as
29/// needed, but can reuse the same buffer for multiple resources if the lifetimes of those buffers
30/// don't overlap
31#[derive(Debug)]
32pub struct RenderGraphBufferResource {
33    pub(super) name: Option<RenderGraphResourceName>,
34
35    pub(super) versions: Vec<RenderGraphBufferResourceVersionInfo>,
36}
37
38impl RenderGraphBufferResource {
39    pub(super) fn new() -> Self {
40        RenderGraphBufferResource {
41            name: None,
42            versions: Default::default(),
43        }
44    }
45}
46
47/// Defines what created a RenderGraphBufferUsage
48#[derive(Debug, Clone, Copy)]
49pub enum RenderGraphBufferUser {
50    Node(RenderGraphNodeId),
51    Input(RenderGraphExternalBufferId),
52    Output(RenderGraphExternalBufferId),
53}
54
55/// A usage of a particular buffer
56#[derive(Debug)]
57pub struct RenderGraphBufferUsage {
58    #[allow(unused)]
59    pub(super) user: RenderGraphBufferUser,
60    pub(super) usage_type: RenderGraphBufferUsageType,
61    pub(super) version: RenderGraphBufferVersionId,
62}
63
64/// Immutable, fully-specified attributes of a buffer. A *constraint* is partially specified and
65/// the graph will use constraints to solve for the specification
66#[derive(Debug, Clone, PartialEq, Eq, Hash)]
67pub struct RenderGraphBufferSpecification {
68    pub size: u64,
69    pub resource_type: RafxResourceType,
70}
71
72impl RenderGraphBufferSpecification {
73    /// Returns true if no fields in the two constraints are conflicting
74    pub fn can_merge(
75        &self,
76        other: &RenderGraphBufferSpecification,
77    ) -> bool {
78        if self.size != other.size {
79            return false;
80        }
81
82        true
83    }
84
85    /// Merge other's constraints into self, but only if there are no conflicts. No modification
86    /// occurs if any conflict exists
87    pub fn try_merge(
88        &mut self,
89        other: &RenderGraphBufferSpecification,
90    ) -> bool {
91        if !self.can_merge(other) {
92            return false;
93        }
94
95        self.resource_type |= other.resource_type;
96
97        true
98    }
99
100    pub fn specifications_are_compatible(
101        written: &RenderGraphBufferSpecification,
102        read: &RenderGraphBufferSpecification,
103    ) -> bool {
104        if written.size != read.size {
105            return false;
106        }
107        if (written.resource_type | read.resource_type) != written.resource_type {
108            return false;
109        }
110        return true;
111    }
112}
113
114/// Constraints on a buffer. Constraints are set per-field and start out None (i.e. unconstrained)
115/// The rendergraph will derive specifications from the constraints
116#[derive(Clone, Debug)]
117pub struct RenderGraphBufferConstraint {
118    // Rename to RenderGraphBufferUsageConstraint?
119    pub size: Option<u64>,
120    pub resource_type: RafxResourceType,
121}
122
123impl Default for RenderGraphBufferConstraint {
124    fn default() -> Self {
125        RenderGraphBufferConstraint {
126            size: None,
127            resource_type: RafxResourceType::UNDEFINED,
128        }
129    }
130}
131
132impl From<RenderGraphBufferSpecification> for RenderGraphBufferConstraint {
133    fn from(specification: RenderGraphBufferSpecification) -> Self {
134        RenderGraphBufferConstraint {
135            size: Some(specification.size),
136            resource_type: specification.resource_type,
137        }
138    }
139}
140
141impl RenderGraphBufferConstraint {
142    pub fn try_convert_to_specification(self) -> Option<RenderGraphBufferSpecification> {
143        // Format is the only thing we can't default sensibly
144        if self.size.is_none() {
145            None
146        } else {
147            Some(RenderGraphBufferSpecification {
148                size: self.size.unwrap(),
149                resource_type: self.resource_type,
150            })
151        }
152    }
153}
154
155impl RenderGraphBufferConstraint {
156    /// Returns true if no fields in the two constraints are conflicting
157    pub fn can_merge(
158        &self,
159        other: &RenderGraphBufferConstraint,
160    ) -> bool {
161        if self.size.is_some() && other.size.is_some() && self.size != other.size {
162            return false;
163        }
164
165        true
166    }
167
168    /// Merge other's constraints into self, but only if there are no conflicts. No modification
169    /// occurs if any conflict exists
170    pub fn try_merge(
171        &mut self,
172        other: &RenderGraphBufferConstraint,
173    ) -> bool {
174        if !self.can_merge(other) {
175            return false;
176        }
177
178        if self.size.is_none() && other.size.is_some() {
179            self.size = other.size;
180        }
181
182        self.resource_type |= other.resource_type;
183
184        true
185    }
186
187    /// Merge other's constraints into self. We will merge fields where we can and skip fields with
188    /// conflicts
189    pub fn partial_merge(
190        &mut self,
191        other: &RenderGraphBufferConstraint,
192    ) -> bool {
193        let mut complete_merge = true;
194
195        if self.size.is_some() && other.size.is_some() && self.size != other.size {
196            complete_merge = false;
197        } else if other.size.is_some() {
198            self.size = other.size;
199        }
200
201        self.resource_type |= other.resource_type;
202
203        complete_merge
204    }
205
206    /// Sets the constraints based on the given specification
207    pub fn set(
208        &mut self,
209        other: &RenderGraphBufferSpecification,
210    ) {
211        *self = other.clone().into();
212    }
213}
214
215/// How a buffer is being used
216#[derive(Copy, Clone, Debug, PartialEq)]
217pub enum RenderGraphBufferUsageType {
218    Create,
219    Input,
220    Read,
221    ModifyRead,
222    ModifyWrite,
223    Output,
224}
225
226impl RenderGraphBufferUsageType {
227    //TODO: Add support to see if multiple writes actually overlap
228    pub fn is_read_only(&self) -> bool {
229        match self {
230            RenderGraphBufferUsageType::Read => true,
231            RenderGraphBufferUsageType::Output => true,
232            RenderGraphBufferUsageType::ModifyRead => false,
233            RenderGraphBufferUsageType::Create => false,
234            RenderGraphBufferUsageType::Input => false,
235            RenderGraphBufferUsageType::ModifyWrite => false,
236        }
237    }
238}
239
240/// Information about a specific version of the buffer.
241#[derive(Debug)]
242pub struct RenderGraphBufferResourceVersionInfo {
243    /// What node created the buffer (keep in mind these are virtual buffers, not buffers provided
244    /// from outside the graph. So every buffer will have a creator node)
245    pub(super) creator_node: RenderGraphNodeId,
246
247    pub(super) create_usage: RenderGraphBufferUsageId,
248    pub(super) read_usages: Vec<RenderGraphBufferUsageId>,
249}
250
251impl RenderGraphBufferResourceVersionInfo {
252    pub(super) fn new(
253        creator: RenderGraphNodeId,
254        create_usage: RenderGraphBufferUsageId,
255    ) -> Self {
256        RenderGraphBufferResourceVersionInfo {
257            creator_node: creator,
258            create_usage,
259            read_usages: Default::default(),
260        }
261    }
262
263    pub(super) fn add_read_usage(
264        &mut self,
265        usage: RenderGraphBufferUsageId,
266    ) {
267        self.read_usages.push(usage);
268    }
269}