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