rendy_chain/chain/
link.rs

1use crate::{
2    node::State,
3    resource::{AccessFlags, Resource},
4    schedule::{QueueId, SubmissionId},
5};
6
7/// State of the link associated with queue.
8/// Contains submissions range, combined access and stages bits by submissions from the range.
9#[derive(Clone, Copy, Debug)]
10pub struct LinkQueueState<R: Resource> {
11    pub first: usize,
12    pub last: usize,
13    pub access: R::Access,
14    pub stages: rendy_core::hal::pso::PipelineStage,
15}
16
17impl<R> LinkQueueState<R>
18where
19    R: Resource,
20{
21    fn new(node: &LinkNode<R>) -> Self {
22        LinkQueueState {
23            first: node.sid.index(),
24            last: node.sid.index(),
25            access: node.state.access,
26            stages: node.state.stages,
27        }
28    }
29
30    fn push(&mut self, node: &LinkNode<R>) {
31        assert!(self.last < node.sid.index());
32        self.access |= node.state.access;
33        self.stages |= node.state.stages;
34        self.last = node.sid.index();
35    }
36}
37
38/// This type defines what states resource are at some point in time when commands recorded into
39/// corresponding submissions are executed.
40/// Those commands doesn't required to perform actions with all access types declared by the link.
41/// But performing actions with access types not declared by the link is prohibited.
42#[derive(Clone, Debug)]
43pub struct Link<R: Resource> {
44    /// Combination of all accesses.
45    access: R::Access,
46
47    /// Combination of all usages.
48    usage: R::Usage,
49
50    /// Common layout for all submissions.
51    layout: R::Layout,
52
53    /// Combination of all stages.
54    stages: rendy_core::hal::pso::PipelineStage,
55
56    /// Number of queues involved.
57    queue_count: usize,
58
59    /// State per queue.
60    queues: Vec<Option<LinkQueueState<R>>>,
61
62    /// Family of queues.
63    family: rendy_core::hal::queue::QueueFamilyId,
64}
65
66/// Node for the link.
67#[derive(Debug)]
68pub struct LinkNode<R: Resource> {
69    /// Submission id of the node.
70    pub sid: SubmissionId,
71
72    /// Resource state of the node.
73    pub state: State<R>,
74}
75
76impl<R> Link<R>
77where
78    R: Resource,
79{
80    /// Create new link with first attached submission.
81    ///
82    /// # Parameters
83    ///
84    /// `access`    - Access flags performed in submission.
85    /// `usage`     - Usage flags required by submission.
86    pub fn new(node: LinkNode<R>) -> Self {
87        let mut link = Link {
88            access: node.state.access,
89            usage: node.state.usage,
90            layout: node.state.layout,
91            stages: node.state.stages,
92            queue_count: 1,
93            queues: Vec::new(),
94            family: node.sid.family(),
95        };
96        link.ensure_queue(node.sid.queue().index());
97        link.queues[node.sid.queue().index()] = Some(LinkQueueState::new(&node));
98        link
99    }
100
101    fn ensure_queue(&mut self, index: usize) {
102        if index >= self.queues.len() {
103            let reserve = index - self.queues.len() + 1;
104            self.queues.reserve(reserve);
105            while index >= self.queues.len() {
106                self.queues.push(None);
107            }
108        }
109    }
110
111    /// Get queue family that owns the resource at the link.
112    /// All associated submissions must be from the same queue family.
113    pub fn family(&self) -> rendy_core::hal::queue::QueueFamilyId {
114        self.family
115    }
116
117    /// Get usage.
118    pub fn submission_state(&self, sid: SubmissionId) -> State<R> {
119        assert_eq!(sid.family(), self.family);
120        let lqs = self.queues[sid.queue().index()].as_ref().unwrap();
121        State {
122            access: lqs.access,
123            layout: self.layout,
124            stages: lqs.stages,
125            usage: self.usage,
126        }
127    }
128
129    /// Get usage.
130    pub fn state(&self) -> State<R> {
131        State {
132            access: self.access,
133            layout: self.layout,
134            stages: self.stages,
135            usage: self.usage,
136        }
137    }
138
139    /// Get access.
140    pub fn access(&self) -> R::Access {
141        self.access
142    }
143
144    /// Get layout.
145    pub fn layout(&self) -> R::Layout {
146        self.layout
147    }
148
149    /// Get usage.
150    pub fn usage(&self) -> R::Usage {
151        self.usage
152    }
153
154    // /// Get usage.
155    // pub fn stages(&self) -> rendy_core::hal::pso::PipelineStage {
156    //     self.stages
157    // }
158
159    /// Check if the link is associated with only one queue.
160    pub fn single_queue(&self) -> bool {
161        self.queue_count == 1
162    }
163
164    /// Check if the given state and submission are compatible with link.
165    /// If compatible then the submission can be associated with the link.
166    pub fn compatible(&self, node: &LinkNode<R>) -> bool {
167        // If queue the same and states are compatible.
168        self.family == node.sid.family() && !(self.access | node.state.access).exclusive()
169    }
170
171    /// Insert submission with specified state to the link.
172    /// It must be compatible.
173    /// Associating submission with the link will allow the submission
174    /// to be executed in parallel with other submissions associated with this link.
175    /// Unless other chains disallow.
176    ///
177    /// # Panics
178    ///
179    /// This function will panic if `state` and `sid` are not compatible.
180    /// E.g. `Link::compatible` didn't return `true` for the arguments.
181    ///
182    pub fn add_node(&mut self, node: LinkNode<R>) {
183        assert_eq!(self.family, node.sid.family());
184        self.ensure_queue(node.sid.queue().index());
185
186        self.access |= node.state.access;
187        self.usage |= node.state.usage;
188        self.stages |= node.state.stages;
189
190        match &mut self.queues[node.sid.queue().index()] {
191            &mut Some(ref mut queue) => {
192                queue.push(&node);
193            }
194            slot @ &mut None => {
195                self.queue_count += 1;
196                *slot = Some(LinkQueueState::new(&node));
197            }
198        }
199    }
200
201    // /// Check if ownership transfer is required between those links.
202    // pub fn transfer_required(&self, next: &Self) -> bool {
203    //     self.family != next.family
204    // }
205
206    /// Iterate over queues.
207    pub fn queues(&self) -> impl Iterator<Item = (QueueId, &LinkQueueState<R>)> {
208        let family = self.family;
209        self.queues
210            .iter()
211            .enumerate()
212            .filter_map(move |(index, queue)| {
213                queue
214                    .as_ref()
215                    .map(move |queue| (QueueId::new(family, index), queue))
216            })
217    }
218
219    /// Get particular queue
220    pub fn queue(&self, qid: QueueId) -> &LinkQueueState<R> {
221        assert_eq!(qid.family(), self.family);
222        self.queues[qid.index()].as_ref().unwrap()
223    }
224}