1use {
2 crate::{
3 chain,
4 command::{Families, FamilyId, QueueId},
5 core::{device_owned, DeviceId},
6 factory::Factory,
7 frame::{Fences, Frame, Frames},
8 memory::Data,
9 node::{
10 BufferBarrier, DynNode, ImageBarrier, NodeBuffer, NodeBuildError, NodeBuilder,
11 NodeImage,
12 },
13 resource::{
14 Buffer, BufferCreationError, BufferInfo, Handle, Image, ImageCreationError, ImageInfo,
15 },
16 BufferId, ImageId, NodeId,
17 },
18 rendy_core::hal::{queue::QueueFamilyId, Backend},
19 thread_profiler::profile_scope,
20};
21
22#[derive(Debug)]
23struct GraphNode<B: Backend, T: ?Sized> {
24 node: Box<dyn DynNode<B, T>>,
25 queue: (usize, usize),
26}
27
28#[derive(Debug)]
30pub struct Graph<B: Backend, T: ?Sized> {
31 device: DeviceId,
32 nodes: Vec<GraphNode<B, T>>,
33 schedule: chain::Schedule<chain::SyncData<usize, usize>>,
34 semaphores: Vec<B::Semaphore>,
35 frames: Frames<B>,
36 fences: Vec<Fences<B>>,
37 inflight: u32,
38 ctx: GraphContext<B>,
39}
40
41device_owned!(Graph<B, T: ?Sized>);
42
43#[derive(Debug)]
45pub enum GraphBuildError {
46 Buffer(BufferCreationError),
48 Image(ImageCreationError),
50 Semaphore(rendy_core::hal::device::OutOfMemory),
52 Node(NodeBuildError),
54}
55
56#[derive(Debug)]
58pub struct GraphContext<B: Backend> {
59 buffers: Vec<Option<Handle<Buffer<B>>>>,
60 images: Vec<
61 Option<(
62 Handle<Image<B>>,
63 Option<rendy_core::hal::command::ClearValue>,
64 )>,
65 >,
66 pub frames_in_flight: u32,
68}
69
70impl<B: Backend> GraphContext<B> {
71 fn alloc<'a>(
72 factory: &Factory<B>,
73 chains: &chain::Chains,
74 buffers: impl IntoIterator<Item = &'a BufferInfo>,
75 images: impl IntoIterator<Item = &'a (ImageInfo, Option<rendy_core::hal::command::ClearValue>)>,
76 frames_in_flight: u32,
77 ) -> Result<Self, GraphBuildError> {
78 profile_scope!("alloc");
79
80 log::trace!("Allocate buffers");
81 let buffers: Vec<Option<Handle<Buffer<B>>>> = buffers
82 .into_iter()
83 .enumerate()
84 .map(|(index, info)| {
85 chains
86 .buffers
87 .get(&chain::Id(index))
88 .map(|buffer| {
89 factory
90 .create_buffer(
91 BufferInfo {
92 usage: buffer.usage(),
93 ..info.clone()
94 },
95 Data,
96 )
97 .map(|buffer| Some(buffer.into()))
98 })
99 .unwrap_or(Ok(None))
100 })
101 .collect::<Result<_, _>>()
102 .map_err(GraphBuildError::Buffer)?;
103
104 log::trace!("Allocate images");
105 let images: Vec<Option<(Handle<Image<B>>, _)>> = images
106 .into_iter()
107 .enumerate()
108 .map(|(index, (info, clear))| {
109 chains
110 .images
111 .get(&chain::Id(index))
112 .map(|image| {
113 factory
114 .create_image(
115 ImageInfo {
116 usage: image.usage(),
117 ..info.clone()
118 },
119 Data,
120 )
121 .map(|image| Some((image.into(), *clear)))
122 })
123 .unwrap_or(Ok(None))
124 })
125 .collect::<Result<_, _>>()
126 .map_err(GraphBuildError::Image)?;
127
128 Ok(Self {
129 buffers,
130 images,
131 frames_in_flight,
132 })
133 }
134
135 pub fn get_image(&self, id: ImageId) -> Option<&Handle<Image<B>>> {
137 self.get_image_with_clear(id).map(|(i, _)| i)
138 }
139
140 pub fn get_image_with_clear(
142 &self,
143 id: ImageId,
144 ) -> Option<(
145 &Handle<Image<B>>,
146 Option<rendy_core::hal::command::ClearValue>,
147 )> {
148 self.images
149 .get(id.0)
150 .and_then(|x| x.as_ref())
151 .map(|&(ref x, ref y)| (&*x, *y))
152 }
153
154 pub fn get_buffer(&self, id: BufferId) -> Option<&Handle<Buffer<B>>> {
156 self.buffers.get(id.0).and_then(|x| x.as_ref()).map(|x| &*x)
157 }
158}
159
160impl<B, T> Graph<B, T>
161where
162 B: Backend,
163 T: ?Sized,
164{
165 pub fn run(&mut self, factory: &mut Factory<B>, families: &mut Families<B>, aux: &T) {
168 profile_scope!("run");
169
170 self.assert_device_owner(factory.device());
171
172 if self.frames.next().index() >= self.inflight as _ {
173 let wait = Frame::with_index(self.frames.next().index() - self.inflight as u64);
174 let ref mut self_fences = self.fences;
175 self.frames.wait_complete(wait, factory, |mut fences| {
176 factory.reset_fences(&mut fences).unwrap();
177 self_fences.push(fences);
178 });
179 }
180
181 let mut fences = self.fences.pop().unwrap_or_else(Fences::<B>::default);
182 let mut fences_used = 0;
183 let ref semaphores = self.semaphores;
184
185 for submission in self.schedule.ordered() {
186 log::trace!("Run node {}", submission.node());
187 let sid = submission.id();
188 let qid = sid.queue();
189
190 let GraphNode { node, queue } = self
191 .nodes
192 .get_mut(submission.node())
193 .expect("Submission references node with out of bound index");
194 debug_assert_eq!(
195 (qid.family(), qid.index()),
196 (QueueFamilyId(queue.0), queue.1),
197 "Node's queue doesn't match schedule"
198 );
199
200 let last_in_queue = sid.index() + 1 == self.schedule.queue(qid).unwrap().len();
201 let fence = if last_in_queue {
202 if fences_used >= fences.len() {
203 fences.push(factory.create_fence(false).unwrap());
204 }
205 fences_used += 1;
206 Some(&mut fences[fences_used - 1])
207 } else {
208 None
209 };
210
211 unsafe {
212 node.run(
213 &self.ctx,
214 factory,
215 families.family_by_index_mut(queue.0).queue_mut(queue.1),
216 aux,
217 &self.frames,
218 &submission
219 .sync()
220 .wait
221 .iter()
222 .map(|wait| {
223 log::trace!(
224 "Node {} waits for {}",
225 submission.node(),
226 *wait.semaphore()
227 );
228 (&semaphores[*wait.semaphore()], wait.stage())
229 })
230 .collect::<smallvec::SmallVec<[_; 16]>>(),
231 &submission
232 .sync()
233 .signal
234 .iter()
235 .map(|signal| {
236 log::trace!(
237 "Node {} signals {}",
238 submission.node(),
239 *signal.semaphore()
240 );
241 &semaphores[*signal.semaphore()]
242 })
243 .collect::<smallvec::SmallVec<[_; 16]>>(),
244 fence,
245 )
246 }
247 }
248
249 fences.truncate(fences_used);
250 self.frames.advance(fences);
251 }
252
253 pub fn node_queue(&self, node: NodeId) -> QueueId {
255 let (f, i) = self.nodes[node.0].queue;
256 QueueId {
257 family: FamilyId {
258 device: self.device,
259 index: f,
260 },
261 index: i,
262 }
263 }
264
265 pub fn dispose(self, factory: &mut Factory<B>, data: &T) {
267 profile_scope!("dispose");
268
269 self.assert_device_owner(factory.device());
270
271 assert!(factory.wait_idle().is_ok());
272 self.frames.dispose(factory);
273
274 unsafe {
275 for node in self.nodes {
277 node.node.dispose(factory, data);
278 }
279
280 for semaphore in self.semaphores {
281 factory.destroy_semaphore(semaphore);
282 }
283 }
284 drop(self.device);
285 drop(self.schedule);
286 drop(self.fences);
287 drop(self.inflight);
288 drop(self.ctx);
289 }
290}
291
292pub struct GraphBuilder<B: Backend, T: ?Sized> {
294 nodes: Vec<Box<dyn NodeBuilder<B, T>>>,
295 buffers: Vec<BufferInfo>,
296 images: Vec<(ImageInfo, Option<rendy_core::hal::command::ClearValue>)>,
297 frames_in_flight: u32,
298}
299
300impl<B, T> Default for GraphBuilder<B, T>
301where
302 B: Backend,
303 T: ?Sized,
304{
305 fn default() -> Self {
306 GraphBuilder {
307 nodes: Vec::default(),
308 buffers: Vec::default(),
309 images: Vec::default(),
310 frames_in_flight: u32::default(),
311 }
312 }
313}
314
315impl<B, T> std::fmt::Debug for GraphBuilder<B, T>
316where
317 B: Backend,
318 T: ?Sized,
319{
320 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 fmt.debug_struct("GraphBuilder")
322 .field("nodes", &self.nodes)
323 .field("buffers", &self.buffers)
324 .field("images", &self.images)
325 .field("frames_in_flight", &self.frames_in_flight)
326 .finish()
327 }
328}
329
330impl<B, T> GraphBuilder<B, T>
331where
332 B: Backend,
333 T: ?Sized,
334{
335 pub fn new() -> Self {
337 GraphBuilder {
338 nodes: Vec::new(),
339 buffers: Vec::new(),
340 images: Vec::new(),
341 frames_in_flight: 3,
342 }
343 }
344
345 pub fn create_buffer(&mut self, size: u64) -> BufferId {
347 profile_scope!("create_buffer");
348
349 self.buffers.push(BufferInfo {
350 size,
351 usage: rendy_core::hal::buffer::Usage::empty(),
352 });
353 BufferId(self.buffers.len() - 1)
354 }
355
356 pub fn create_image(
358 &mut self,
359 kind: rendy_core::hal::image::Kind,
360 levels: rendy_core::hal::image::Level,
361 format: rendy_core::hal::format::Format,
362 clear: Option<rendy_core::hal::command::ClearValue>,
363 ) -> ImageId {
364 profile_scope!("create_image");
365
366 self.images.push((
367 ImageInfo {
368 kind,
369 levels,
370 format,
371 tiling: rendy_core::hal::image::Tiling::Optimal,
372 view_caps: rendy_core::hal::image::ViewCapabilities::empty(),
373 usage: rendy_core::hal::image::Usage::empty(),
374 },
375 clear,
376 ));
377 ImageId(self.images.len() - 1)
378 }
379
380 pub fn add_node<N: NodeBuilder<B, T> + 'static>(&mut self, builder: N) -> NodeId {
382 self.add_dyn_node(Box::new(builder))
383 }
384
385 pub fn add_dyn_node(&mut self, builder: Box<dyn NodeBuilder<B, T> + 'static>) -> NodeId {
387 self.nodes.push(builder);
388 NodeId(self.nodes.len() - 1)
389 }
390
391 pub fn with_frames_in_flight(mut self, frames_in_flight: u32) -> Self {
393 self.frames_in_flight = frames_in_flight;
394 self
395 }
396
397 pub fn build(
409 self,
410 factory: &mut Factory<B>,
411 families: &mut Families<B>,
412 aux: &T,
413 ) -> Result<Graph<B, T>, GraphBuildError> {
414 profile_scope!("build");
415
416 log::trace!("Schedule nodes execution");
417 let chain_nodes: Vec<chain::Node> = {
418 profile_scope!("schedule_nodes");
419 self.nodes
420 .iter()
421 .enumerate()
422 .map(|(i, b)| make_chain_node(&**b, i, factory, families))
423 .collect()
424 };
425
426 let chains = chain::collect(chain_nodes, |id| {
427 families.family_by_index(id.0).as_slice().len()
428 });
429 log::trace!("Scheduled nodes execution {:#?}", chains);
430
431 let mut ctx = GraphContext::alloc(
432 factory,
433 &chains,
434 &self.buffers,
435 &self.images,
436 self.frames_in_flight,
437 )?;
438
439 log::trace!("Synchronize");
440
441 let mut semaphores = 0..;
442 let mut schedule = chain::sync(&chains, || {
443 let id = semaphores.next().unwrap();
444 (id, id)
445 });
446 schedule.build_order();
447 log::trace!("Schedule: {:#?}", schedule);
448
449 log::trace!("Build nodes");
450 let mut built_nodes: Vec<_> = (0..self.nodes.len()).map(|_| None).collect();
451 let mut node_descs: Vec<_> = self.nodes.into_iter().map(Some).collect();
452
453 {
454 profile_scope!("build_nodes");
455
456 for family in schedule.iter() {
457 log::trace!("For family {:#?}", family);
458 for queue in family.iter() {
459 log::trace!("For queue {:#?}", queue.id());
460 for submission in queue.iter() {
461 log::trace!("For submission {:#?}", submission.id());
462 let builder = node_descs[submission.node()].take().unwrap();
463 log::trace!("Build node {:#?}", builder);
464 let node = build_node(
465 &mut ctx,
466 builder,
467 factory,
468 families.family_by_index_mut(family.id().0),
469 queue.id().index(),
470 aux,
471 &chains,
472 &submission,
473 )
474 .map_err(GraphBuildError::Node)?;
475 log::debug!("Node built: {:#?}", node);
476 built_nodes[submission.node()] = Some((node, submission.id().queue()));
477 }
478 }
479 }
480 }
481
482 log::debug!("Create {} semaphores", semaphores.start);
483 let semaphores = (0..semaphores.start)
484 .map(|_| factory.create_semaphore())
485 .collect::<Result<_, _>>()
486 .map_err(GraphBuildError::Semaphore)?;
487
488 Ok(Graph {
489 device: factory.device().id(),
490 ctx,
491 nodes: built_nodes
492 .into_iter()
493 .map(Option::unwrap)
494 .map(|(node, qid)| GraphNode {
495 node,
496 queue: (qid.family().0, qid.index()),
497 })
498 .collect(),
499 schedule,
500 semaphores,
501 inflight: self.frames_in_flight,
502 frames: Frames::new(),
503 fences: Vec::new(),
504 })
505 }
506}
507
508fn build_node<'a, B: Backend, T: ?Sized>(
509 ctx: &GraphContext<B>,
510 builder: Box<dyn NodeBuilder<B, T>>,
511 factory: &mut Factory<B>,
512 family: &mut rendy_command::Family<B>,
513 queue: usize,
514 aux: &T,
515 chains: &chain::Chains,
516 submission: &chain::Submission<chain::SyncData<usize, usize>>,
517) -> Result<Box<dyn DynNode<B, T>>, NodeBuildError> {
518 let mut buffer_ids: Vec<_> = builder.buffers().into_iter().map(|(id, _)| id).collect();
519 buffer_ids.sort();
520 buffer_ids.dedup();
521
522 let buffers: Vec<_> = buffer_ids
523 .into_iter()
524 .map(|id| {
525 let chain_id = chain::Id(id.0);
526 let sync = submission.sync();
527 let buffer = ctx
528 .get_buffer(id)
529 .expect("Buffer referenced from at least one node must be instantiated");
530 NodeBuffer {
531 id,
532 range: 0..buffer.size(),
533 acquire: sync.acquire.buffers.get(&chain_id).map(
534 |chain::Barrier { states, families }| BufferBarrier {
535 states: states.start.0..states.end.0,
536 stages: states.start.2..states.end.2,
537 families: families.clone(),
538 },
539 ),
540 release: sync.release.buffers.get(&chain_id).map(
541 |chain::Barrier { states, families }| BufferBarrier {
542 states: states.start.0..states.end.0,
543 stages: states.start.2..states.end.2,
544 families: families.clone(),
545 },
546 ),
547 }
548 })
549 .collect();
550
551 let mut image_ids: Vec<_> = builder.images().into_iter().map(|(id, _)| id).collect();
552 image_ids.sort();
553 image_ids.dedup();
554
555 let images: Vec<_> = image_ids
556 .into_iter()
557 .map(|id| {
558 let chain_id = chain::Id(id.0);
559 let sync = submission.sync();
560 let link = submission.image_link_index(chain_id);
561 let (image, clear) = ctx
562 .get_image_with_clear(id)
563 .expect("Image referenced from at least one node must be instantiated");
564 NodeImage {
565 id,
566 range: rendy_core::hal::image::SubresourceRange {
567 aspects: image.format().surface_desc().aspects,
568 levels: 0..image.levels(),
569 layers: 0..image.layers(),
570 },
571 layout: chains.images[&chain_id].links()[link]
572 .submission_state(submission.id())
573 .layout,
574 clear: if link == 0 { clear } else { None },
575 acquire: sync.acquire.images.get(&chain_id).map(
576 |chain::Barrier { states, families }| ImageBarrier {
577 states: (
578 states.start.0,
579 if link == 0 {
580 rendy_core::hal::image::Layout::Undefined
581 } else {
582 states.start.1
583 },
584 )..(states.end.0, states.end.1),
585 stages: states.start.2..states.end.2,
586 families: families.clone(),
587 },
588 ),
589 release: sync.release.images.get(&chain_id).map(
590 |chain::Barrier { states, families }| ImageBarrier {
591 states: (states.start.0, states.start.1)..(states.end.0, states.end.1),
592 stages: states.start.2..states.end.2,
593 families: families.clone(),
594 },
595 ),
596 }
597 })
598 .collect();
599 builder.build(ctx, factory, family, queue, aux, buffers, images)
600}
601
602fn make_chain_node<B, T>(
603 builder: &dyn NodeBuilder<B, T>,
604 id: usize,
605 factory: &mut Factory<B>,
606 families: &Families<B>,
607) -> chain::Node
608where
609 B: Backend,
610 T: ?Sized,
611{
612 let buffers = builder.buffers();
613 let images = builder.images();
614 chain::Node {
615 id,
616 family: QueueFamilyId(builder.family(factory, families).unwrap().index),
617 dependencies: builder.dependencies().into_iter().map(|id| id.0).collect(),
618 buffers: buffers
619 .into_iter()
620 .map(|(id, access)| {
621 (
622 chain::Id(id.0),
623 chain::BufferState {
624 access: access.access,
625 stages: access.stages,
626 layout: (),
627 usage: access.usage,
628 },
629 )
630 })
631 .collect(),
632 images: images
633 .into_iter()
634 .map(|(id, access)| {
635 (
636 chain::Id(id.0),
637 chain::ImageState {
638 access: access.access,
639 stages: access.stages,
640 layout: access.layout,
641 usage: access.usage,
642 },
643 )
644 })
645 .collect(),
646 }
647}