1use std::cmp::max;
2use std::collections::hash_map::RandomState;
3use std::collections::HashMap;
4use std::hash::Hash;
5use std::ops::Range;
6
7use crate::{
8 chain::{BufferChains, Chain, ImageChains, Link, LinkNode},
9 node::{Node, State},
10 resource::{Buffer, Image, Resource},
11 schedule::{Queue, QueueId, Schedule, Submission, SubmissionId},
12 Id,
13};
14
15#[derive(Clone, Copy, Debug)]
17pub struct Unsynchronized;
18
19#[derive(Debug)]
21pub struct Chains {
22 pub schedule: Schedule<Unsynchronized>,
24
25 pub buffers: BufferChains,
27
28 pub images: ImageChains,
30}
31
32#[derive(PartialEq, PartialOrd, Eq, Ord)]
33struct Fitness {
34 transfers: usize,
35 wait_factor: usize,
36}
37
38struct ResolvedNode {
39 id: usize,
40 family: rendy_core::hal::queue::QueueFamilyId,
41 queues: Range<usize>,
42 rev_deps: Vec<usize>,
43 buffers: Vec<(usize, State<Buffer>)>,
44 images: Vec<(usize, State<Image>)>,
45}
46
47impl Default for ResolvedNode {
48 fn default() -> Self {
49 ResolvedNode {
50 id: 0,
51 family: rendy_core::hal::queue::QueueFamilyId(0),
52 queues: 0..0,
53 rev_deps: Vec::new(),
54 buffers: Vec::new(),
55 images: Vec::new(),
56 }
57 }
58}
59
60struct ResolvedNodeSet {
61 nodes: Vec<ResolvedNode>,
62 queues: Vec<QueueId>,
63 buffers: Vec<Id>,
64 images: Vec<Id>,
65}
66
67struct ChainData<R: Resource> {
68 chain: Chain<R>,
69 last_link_wait_factor: usize,
70 current_link_wait_factor: usize,
71 current_family: Option<rendy_core::hal::queue::QueueFamilyId>,
72}
73impl<R: Resource> Default for ChainData<R> {
74 fn default() -> Self {
75 ChainData {
76 chain: Chain::new(),
77 last_link_wait_factor: 0,
78 current_link_wait_factor: 0,
79 current_family: None,
80 }
81 }
82}
83
84struct QueueData {
85 queue: Queue<Unsynchronized>,
86 wait_factor: usize,
87}
88
89pub fn collect<Q>(nodes: Vec<Node>, max_queues: Q) -> Chains
92where
93 Q: Fn(rendy_core::hal::queue::QueueFamilyId) -> usize,
94{
95 let (nodes, mut unscheduled_nodes) = resolve_nodes(nodes, max_queues);
97 let mut ready_nodes = Vec::new();
98
99 let mut images: Vec<ChainData<Image>> = fill(nodes.images.len());
101 let mut buffers: Vec<ChainData<Buffer>> = fill(nodes.buffers.len());
102
103 let mut schedule = Vec::with_capacity(nodes.queues.len());
105 for i in 0..nodes.queues.len() {
106 schedule.push(QueueData {
107 queue: Queue::new(nodes.queues[i]),
108 wait_factor: 0,
109 });
110 }
111
112 for node in &nodes.nodes {
113 if unscheduled_nodes[node.id] == 0 {
114 ready_nodes.push(node);
115 }
116 }
117
118 let mut scheduled = 0;
119 if nodes.queues.len() == 1 {
120 while let Some(node) = ready_nodes.pop() {
123 schedule_node(
124 &mut ready_nodes,
125 &mut unscheduled_nodes,
126 &nodes,
127 node,
128 0,
129 scheduled,
130 scheduled,
131 &mut schedule,
132 &mut images,
133 &mut buffers,
134 );
135 scheduled += 1;
136 }
137 } else {
138 while !ready_nodes.is_empty() {
139 let (fitness, qid, index) = ready_nodes
141 .iter()
142 .enumerate()
143 .map(|(index, &node)| {
144 let (fitness, qid) = fitness(node, &mut images, &mut buffers, &mut schedule);
145 (fitness, qid, index)
146 })
147 .min()
148 .unwrap();
149
150 let node = ready_nodes.swap_remove(index);
151 schedule_node(
152 &mut ready_nodes,
153 &mut unscheduled_nodes,
154 &nodes,
155 node,
156 qid,
157 fitness.wait_factor,
158 scheduled,
159 &mut schedule,
160 &mut images,
161 &mut buffers,
162 );
163 scheduled += 1;
164 }
165 }
166 assert_eq!(scheduled, nodes.nodes.len(), "Dependency loop found!");
167
168 Chains {
169 schedule: reify_schedule(schedule),
170 buffers: reify_chain(&nodes.buffers, buffers),
171 images: reify_chain(&nodes.images, images),
172 }
173}
174
175fn fill<T: Default>(num: usize) -> Vec<T> {
176 let mut vec = Vec::with_capacity(num);
177 for _ in 0..num {
178 vec.push(T::default());
179 }
180 vec
181}
182
183struct LookupBuilder<I: Hash + Eq + Copy> {
184 forward: HashMap<I, usize>,
185 backward: Vec<I>,
186}
187impl<I: Hash + Eq + Copy> LookupBuilder<I> {
188 fn new() -> LookupBuilder<I> {
189 LookupBuilder {
190 forward: HashMap::default(),
191 backward: Vec::new(),
192 }
193 }
194
195 fn forward(&mut self, id: I) -> usize {
196 if let Some(&id_num) = self.forward.get(&id) {
197 id_num
198 } else {
199 let id_num = self.backward.len();
200 self.backward.push(id);
201 self.forward.insert(id, id_num);
202 id_num
203 }
204 }
205}
206
207fn resolve_nodes<Q>(nodes: Vec<Node>, max_queues: Q) -> (ResolvedNodeSet, Vec<usize>)
208where
209 Q: Fn(rendy_core::hal::queue::QueueFamilyId) -> usize,
210{
211 let node_count = nodes.len();
212
213 let mut unscheduled_nodes = fill(nodes.len());
214 let mut reified_nodes: Vec<ResolvedNode> = fill(nodes.len());
215 let mut node_ids = LookupBuilder::new();
216 let mut queues = LookupBuilder::new();
217 let mut buffers = LookupBuilder::new();
218 let mut images = LookupBuilder::new();
219
220 let s = RandomState::new();
221 let mut family_full = HashMap::with_hasher(s);
222
223 for node in nodes {
224 let family = node.family;
225 if !family_full.contains_key(&family) {
226 let count = max_queues(family);
227 assert!(count > 0, "Cannot create a family with 0 max queues.");
228 for i in 0..count {
229 queues.forward(QueueId::new(family, i));
230 }
231
232 let full_range = queues.forward(QueueId::new(family, 0))
233 ..queues.forward(QueueId::new(family, count - 1)) + 1;
234 family_full.insert(family, full_range);
235 }
236
237 let id = node_ids.forward(node.id);
238 assert!(id < node_count, "Dependency not found."); let unscheduled_count = node.dependencies.len();
240
241 for dep in node.dependencies {
242 reified_nodes[node_ids.forward(dep)].rev_deps.push(id);
245 }
246 unscheduled_nodes[id] = unscheduled_count;
247
248 reified_nodes[id].id = id;
250 reified_nodes[id].family = node.family;
251 reified_nodes[id].queues = family_full[&family].clone();
252 reified_nodes[id].buffers = node
253 .buffers
254 .into_iter()
255 .map(|(k, v)| (buffers.forward(k), v))
256 .collect();
257 reified_nodes[id].images = node
258 .images
259 .into_iter()
260 .map(|(k, v)| (images.forward(k), v))
261 .collect();
262 }
263
264 (
265 ResolvedNodeSet {
266 nodes: reified_nodes,
267 queues: queues.backward,
268 buffers: buffers.backward,
269 images: images.backward,
270 },
271 unscheduled_nodes,
272 )
273}
274
275fn reify_chain<R: Resource>(ids: &[Id], vec: Vec<ChainData<R>>) -> HashMap<Id, Chain<R>> {
276 let mut map = HashMap::with_capacity_and_hasher(vec.len(), Default::default());
277 for (chain, &i) in vec.into_iter().zip(ids) {
278 map.insert(i, chain.chain);
279 }
280 map
281}
282
283fn reify_schedule(vec: Vec<QueueData>) -> Schedule<Unsynchronized> {
284 let mut schedule = Schedule::new();
285 for queue_data in vec.into_iter() {
286 schedule.set_queue(queue_data.queue);
287 }
288 schedule
289}
290
291fn fitness(
292 node: &ResolvedNode,
293 images: &mut Vec<ChainData<Image>>,
294 buffers: &mut Vec<ChainData<Buffer>>,
295 schedule: &mut Vec<QueueData>,
296) -> (Fitness, usize) {
297 let mut transfers = 0;
298 let mut wait_factor_from_chains = 0;
299
300 for &(id, _) in &node.buffers {
302 let chain = &buffers[id];
303 if chain
304 .current_family
305 .map_or(false, |family| family != node.family)
306 {
307 transfers += 1;
308 }
309 wait_factor_from_chains = max(wait_factor_from_chains, chain.last_link_wait_factor);
310 }
311 for &(id, _) in &node.images {
312 let chain = &images[id];
313 if chain
314 .current_family
315 .map_or(false, |family| family != node.family)
316 {
317 transfers += 1;
318 }
319 wait_factor_from_chains = max(wait_factor_from_chains, chain.last_link_wait_factor);
320 }
321
322 let (wait_factor_from_queue, queue) = node
324 .queues
325 .clone()
326 .map(|index| (schedule[index].wait_factor, index))
327 .min()
328 .unwrap();
329 (
330 Fitness {
331 transfers,
332 wait_factor: max(wait_factor_from_chains, wait_factor_from_queue),
333 },
334 queue,
335 )
336}
337
338fn schedule_node<'a>(
339 ready_nodes: &mut Vec<&'a ResolvedNode>,
340 unscheduled_nodes: &mut Vec<usize>,
341 nodes: &'a ResolvedNodeSet,
342 node: &ResolvedNode,
343 queue: usize,
344 wait_factor: usize,
345 submitted: usize,
346 schedule: &mut Vec<QueueData>,
347 images: &mut Vec<ChainData<Image>>,
348 buffers: &mut Vec<ChainData<Buffer>>,
349) {
350 let ref mut queue_data = schedule[queue];
351 queue_data.wait_factor = max(queue_data.wait_factor, wait_factor + 1);
352 let sid = queue_data
353 .queue
354 .add_submission(node.id, wait_factor, submitted, Unsynchronized);
355 let submission = queue_data.queue.submission_mut(sid).unwrap();
356
357 for &(id, state) in &node.buffers {
358 add_to_chain(
359 nodes.buffers[id],
360 node.family,
361 &mut buffers[id],
362 sid,
363 submission,
364 state,
365 |s, i, l| s.set_buffer_link(i, l),
366 );
367 }
368 for &(id, state) in &node.images {
369 add_to_chain(
370 nodes.images[id],
371 node.family,
372 &mut images[id],
373 sid,
374 submission,
375 state,
376 |s, i, l| s.set_image_link(i, l),
377 );
378 }
379
380 for &rev_dep in &node.rev_deps {
381 unscheduled_nodes[rev_dep] -= 1;
382 if unscheduled_nodes[rev_dep] == 0 {
383 ready_nodes.push(&nodes.nodes[rev_dep]);
384 }
385 }
386}
387
388fn add_to_chain<R, S>(
389 id: Id,
390 family: rendy_core::hal::queue::QueueFamilyId,
391 chain_data: &mut ChainData<R>,
392 sid: SubmissionId,
393 submission: &mut Submission<S>,
394 state: State<R>,
395 set_link: impl FnOnce(&mut Submission<S>, Id, usize),
396) where
397 R: Resource,
398{
399 let node = LinkNode { sid, state };
400
401 chain_data.current_family = Some(family);
402 chain_data.current_link_wait_factor = max(
403 submission.wait_factor() + 1,
404 chain_data.current_link_wait_factor,
405 );
406
407 let ref mut chain = chain_data.chain;
408 let chain_len = chain.links().len();
409 let append = match chain.last_link_mut() {
410 Some(ref mut link) if link.compatible(&node) => {
411 set_link(submission, id, chain_len - 1);
412 link.add_node(node);
413 None
414 }
415 Some(_) | None => {
416 set_link(submission, id, chain_len);
417 chain_data.last_link_wait_factor = chain_data.current_link_wait_factor;
418 Some(Link::new(node))
419 }
420 };
421
422 if let Some(link) = append {
423 chain.add_link(link);
424 }
425}