1use {
2 crate::{
3 command::{
4 CommandBuffer, CommandPool, ExecutableState, Families, Family, FamilyId, Fence,
5 Graphics, IndividualReset, MultiShot, NoSimultaneousUse, PendingState, Queue, QueueId,
6 SecondaryLevel, SimultaneousUse, Submission, Submit,
7 },
8 core::{
9 hal::{device::Device as _, image::Layout, Backend},
10 uses_pipeline_barriers,
11 },
12 factory::Factory,
13 frame::{
14 cirque::{CirqueRef, CommandCirque},
15 Frames,
16 },
17 graph::GraphContext,
18 node::{
19 gfx_acquire_barriers, gfx_release_barriers,
20 render::group::{RenderGroup, RenderGroupBuilder},
21 BufferAccess, DynNode, ImageAccess, NodeBuffer, NodeBuildError, NodeBuilder, NodeImage,
22 },
23 wsi::{Surface, Target},
24 BufferId, ImageId, NodeId,
25 },
26 either::Either,
27 std::{cmp::min, collections::HashMap},
28};
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
31struct RenderPassSurface;
32
33type Attachment = Either<ImageId, RenderPassSurface>;
34
35pub struct SubpassBuilder<B: Backend, T: ?Sized> {
37 groups: Vec<Box<dyn RenderGroupBuilder<B, T>>>,
38 inputs: Vec<Attachment>,
39 colors: Vec<Attachment>,
40 depth_stencil: Option<Attachment>,
41 dependencies: Vec<NodeId>,
42}
43
44impl<B, T> std::fmt::Debug for SubpassBuilder<B, T>
45where
46 B: Backend,
47 T: ?Sized,
48{
49 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 fmt.debug_struct("SubpassBuilder")
51 .field("groups", &self.groups)
52 .field("inputs", &self.inputs)
53 .field("colors", &self.colors)
54 .field("depth_stencil", &self.depth_stencil)
55 .field("dependencies", &self.dependencies)
56 .finish()
57 }
58}
59
60impl<B, T> Default for SubpassBuilder<B, T>
61where
62 B: Backend,
63 T: ?Sized,
64{
65 fn default() -> Self {
66 SubpassBuilder {
67 groups: Vec::default(),
68 inputs: Vec::default(),
69 colors: Vec::default(),
70 depth_stencil: None,
71 dependencies: Vec::default(),
72 }
73 }
74}
75
76impl<B, T> SubpassBuilder<B, T>
77where
78 B: Backend,
79 T: ?Sized,
80{
81 pub fn new() -> Self {
83 Self::default()
84 }
85
86 pub fn add_group<R>(&mut self, group: R) -> &mut Self
88 where
89 R: RenderGroupBuilder<B, T> + 'static,
90 {
91 self.groups.push(Box::new(group));
92 self
93 }
94
95 pub fn with_group<R>(mut self, group: R) -> Self
97 where
98 R: RenderGroupBuilder<B, T> + 'static,
99 {
100 self.add_group(group);
101 self
102 }
103
104 pub fn add_dyn_group(&mut self, group: Box<dyn RenderGroupBuilder<B, T>>) -> &mut Self {
106 self.groups.push(group);
107 self
108 }
109
110 pub fn with_dyn_group(mut self, group: Box<dyn RenderGroupBuilder<B, T>>) -> Self {
112 self.add_dyn_group(group);
113 self
114 }
115
116 pub fn add_input(&mut self, input: ImageId) -> &mut Self {
118 self.inputs.push(Either::Left(input));
119 self
120 }
121
122 pub fn with_input(mut self, input: ImageId) -> Self {
124 self.add_input(input);
125 self
126 }
127
128 pub fn add_color(&mut self, color: ImageId) -> &mut Self {
130 self.colors.push(Either::Left(color));
131 self
132 }
133
134 pub fn with_color(mut self, color: ImageId) -> Self {
136 self.add_color(color);
137 self
138 }
139
140 pub fn add_color_surface(&mut self) -> &mut Self {
142 self.colors.push(Either::Right(RenderPassSurface));
143 self
144 }
145
146 pub fn with_color_surface(mut self) -> Self {
148 self.add_color_surface();
149 self
150 }
151
152 pub fn set_depth_stencil(&mut self, depth_stencil: ImageId) -> &mut Self {
154 self.depth_stencil = Some(Either::Left(depth_stencil));
155 self
156 }
157
158 pub fn with_depth_stencil(mut self, depth_stencil: ImageId) -> Self {
160 self.set_depth_stencil(depth_stencil);
161 self
162 }
163
164 pub fn set_depth_stencil_surface(&mut self) -> &mut Self {
166 self.depth_stencil = Some(Either::Right(RenderPassSurface));
167 self
168 }
169
170 pub fn with_depth_stencil_surface(mut self) -> Self {
172 self.set_depth_stencil_surface();
173 self
174 }
175
176 pub fn add_dependency(&mut self, dependency: NodeId) -> &mut Self {
179 self.dependencies.push(dependency);
180 self
181 }
182
183 pub fn with_dependency(mut self, dependency: NodeId) -> Self {
186 self.add_dependency(dependency);
187 self
188 }
189
190 pub fn into_pass(self) -> RenderPassNodeBuilder<B, T> {
192 RenderPassNodeBuilder::new().with_subpass(self)
193 }
194}
195
196pub struct RenderPassNodeBuilder<B: Backend, T: ?Sized> {
198 subpasses: Vec<SubpassBuilder<B, T>>,
199 surface: Option<(
200 Surface<B>,
201 rendy_core::hal::window::Extent2D,
202 Option<rendy_core::hal::command::ClearValue>,
203 )>,
204}
205
206impl<B, T> std::fmt::Debug for RenderPassNodeBuilder<B, T>
207where
208 B: Backend,
209 T: ?Sized,
210{
211 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 fmt.debug_struct("RenderPassNodeBuilder")
213 .field("subpasses", &self.subpasses)
214 .field("surface", &self.surface)
215 .finish()
216 }
217}
218
219impl<B, T> Default for RenderPassNodeBuilder<B, T>
220where
221 B: Backend,
222 T: ?Sized,
223{
224 fn default() -> Self {
225 RenderPassNodeBuilder {
226 subpasses: Vec::default(),
227 surface: None,
228 }
229 }
230}
231
232impl<B, T> RenderPassNodeBuilder<B, T>
233where
234 B: Backend,
235 T: ?Sized,
236{
237 pub fn new() -> Self {
239 Self::default()
240 }
241
242 pub fn add_subpass(&mut self, subpass: SubpassBuilder<B, T>) -> &mut Self {
244 self.subpasses.push(subpass);
245 self
246 }
247
248 pub fn with_subpass(mut self, subpass: SubpassBuilder<B, T>) -> Self {
250 self.add_subpass(subpass);
251 self
252 }
253
254 pub fn add_surface(
256 &mut self,
257 surface: Surface<B>,
258 suggested_extent: rendy_core::hal::window::Extent2D,
259 clear: Option<rendy_core::hal::command::ClearValue>,
260 ) -> &mut Self {
261 assert!(
262 self.surface.is_none(),
263 "Only one surface can be attachend to rende pass"
264 );
265 self.surface = Some((surface, suggested_extent, clear));
266 self
267 }
268
269 pub fn with_surface(
271 mut self,
272 surface: Surface<B>,
273 suggested_extent: rendy_core::hal::window::Extent2D,
274 clear: Option<rendy_core::hal::command::ClearValue>,
275 ) -> Self {
276 self.add_surface(surface, suggested_extent, clear);
277 self
278 }
279}
280
281impl<B, T> NodeBuilder<B, T> for RenderPassNodeBuilder<B, T>
282where
283 B: Backend,
284 T: ?Sized + 'static,
285{
286 fn family(&self, _factory: &mut Factory<B>, families: &Families<B>) -> Option<FamilyId> {
287 families.with_capability::<Graphics>()
288 }
289
290 fn buffers(&self) -> Vec<(BufferId, BufferAccess)> {
291 let empty = BufferAccess {
292 access: rendy_core::hal::buffer::Access::empty(),
293 usage: rendy_core::hal::buffer::Usage::empty(),
294 stages: rendy_core::hal::pso::PipelineStage::empty(),
295 };
296 let mut buffers = HashMap::new();
297
298 for subpass in &self.subpasses {
299 for group in &subpass.groups {
300 for (index, access) in group.buffers() {
301 let entry = buffers.entry(index).or_insert(empty);
302 entry.access |= access.access;
303 entry.usage |= access.usage;
304 entry.stages |= access.stages;
305 }
306 }
307 }
308
309 buffers.into_iter().collect()
310 }
311
312 fn images(&self) -> Vec<(ImageId, ImageAccess)> {
313 let empty = ImageAccess {
314 access: rendy_core::hal::image::Access::empty(),
315 usage: rendy_core::hal::image::Usage::empty(),
316 stages: rendy_core::hal::pso::PipelineStage::empty(),
317 layout: Layout::Undefined,
318 };
319 let mut attachments = HashMap::new();
320 let mut images = HashMap::new();
321
322 for subpass in &self.subpasses {
323 for &id in subpass.inputs.iter().filter_map(|e| e.as_ref().left()) {
324 let entry = attachments.entry(id).or_insert(ImageAccess {
325 layout: Layout::ShaderReadOnlyOptimal,
326 ..empty
327 });
328 entry.access |= rendy_core::hal::image::Access::INPUT_ATTACHMENT_READ;
329 entry.usage |= rendy_core::hal::image::Usage::INPUT_ATTACHMENT;
330 entry.stages |= rendy_core::hal::pso::PipelineStage::FRAGMENT_SHADER;
331 }
332
333 for &id in subpass.colors.iter().filter_map(|e| e.as_ref().left()) {
334 let entry = attachments.entry(id).or_insert(ImageAccess {
335 layout: Layout::ColorAttachmentOptimal,
336 ..empty
337 });
338 entry.access |= rendy_core::hal::image::Access::COLOR_ATTACHMENT_READ
339 | rendy_core::hal::image::Access::COLOR_ATTACHMENT_WRITE;
340 entry.usage |= rendy_core::hal::image::Usage::COLOR_ATTACHMENT;
341 entry.stages |= rendy_core::hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT;
342 }
343
344 if let Some(id) = subpass.depth_stencil.and_then(Either::left) {
345 let entry = attachments.entry(id).or_insert(ImageAccess {
346 layout: Layout::DepthStencilAttachmentOptimal,
347 ..empty
348 });
349 entry.access |= rendy_core::hal::image::Access::DEPTH_STENCIL_ATTACHMENT_READ
350 | rendy_core::hal::image::Access::DEPTH_STENCIL_ATTACHMENT_WRITE;
351 entry.usage |= rendy_core::hal::image::Usage::DEPTH_STENCIL_ATTACHMENT;
352 entry.stages |= rendy_core::hal::pso::PipelineStage::EARLY_FRAGMENT_TESTS
353 | rendy_core::hal::pso::PipelineStage::LATE_FRAGMENT_TESTS;
354 }
355
356 for group in &subpass.groups {
357 for (id, access) in group.images() {
358 assert!(
359 !attachments.contains_key(&id),
360 "Attachment image can't be used otherwise in render pass"
361 );
362 let entry = images.entry(id).or_insert(empty);
363 entry.access |= access.access;
364 entry.usage |= access.usage;
365 entry.stages |= access.stages;
366 entry.layout = common_layout(entry.layout, access.layout);
367 }
368 }
369 }
370
371 attachments.into_iter().chain(images.into_iter()).collect()
372 }
373
374 fn dependencies(&self) -> Vec<NodeId> {
375 let mut dependencies: Vec<_> = self
376 .subpasses
377 .iter()
378 .flat_map(|subpass| {
379 subpass
380 .dependencies
381 .iter()
382 .cloned()
383 .chain(subpass.groups.iter().flat_map(|group| group.dependencies()))
384 })
385 .collect();
386 dependencies.sort();
387 dependencies.dedup();
388 dependencies
389 }
390
391 fn build<'a>(
392 self: Box<Self>,
393 ctx: &GraphContext<B>,
394 factory: &mut Factory<B>,
395 family: &mut Family<B>,
396 queue: usize,
397 aux: &T,
398 buffers: Vec<NodeBuffer>,
399 images: Vec<NodeImage>,
400 ) -> Result<Box<dyn DynNode<B, T>>, NodeBuildError> {
401 use rendy_core::hal::window::PresentMode;
402
403 let mut surface_color_usage = false;
404 let mut surface_depth_usage = false;
405
406 let (mut surface, suggested_extent, surface_clear) = self
407 .surface
408 .map_or((None, None, None), |(s, e, c)| (Some(s), Some(e), c));
409 log::debug!(
410 "Build render pass node {} surface",
411 surface.as_ref().map_or("without", |_| "with")
412 );
413
414 let mut attachments: Vec<Attachment> = self
415 .subpasses
416 .iter()
417 .flat_map(|subpass| {
418 subpass
419 .inputs
420 .iter()
421 .chain(subpass.colors.iter().inspect(|a| {
422 surface_color_usage = surface_color_usage || a.is_right();
423 }))
424 .chain(subpass.depth_stencil.as_ref().into_iter().inspect(|a| {
425 surface_depth_usage = surface_depth_usage || a.is_right();
426 }))
427 .cloned()
428 .collect::<Vec<_>>()
429 })
430 .collect();
431
432 let mut surface_usage = rendy_core::hal::image::Usage::empty();
433 if surface_color_usage {
434 surface_usage |= rendy_core::hal::image::Usage::COLOR_ATTACHMENT;
435 }
436 if surface_depth_usage {
437 surface_usage |= rendy_core::hal::image::Usage::DEPTH_STENCIL_ATTACHMENT;
438 }
439
440 if surface.is_some() {
441 log::debug!("Surface usage {:#?}", surface_usage);
442 } else {
443 debug_assert_eq!(surface_usage, rendy_core::hal::image::Usage::empty());
444 }
445
446 attachments.sort();
447 attachments.dedup();
448
449 let find_attachment_node_image = |id: ImageId| -> &NodeImage {
450 images
451 .iter()
452 .find(|a| a.id == id)
453 .expect("Attachment image wasn't provided")
454 };
455
456 let mut framebuffer_width = u32::max_value();
457 let mut framebuffer_height = u32::max_value();
458 let mut framebuffer_layers = u16::max_value();
459
460 let mut node_target = None;
461
462 log::trace!("Configure attachments");
463
464 let views: Vec<_> = attachments
465 .iter()
466 .map(|&attachment| -> Result<Vec<_>, NodeBuildError> {
467 match attachment {
468 Either::Left(image_id) => {
469 log::debug!("Image {:?} attachment", image_id);
470
471 let node_image = find_attachment_node_image(image_id);
472 let image = ctx.get_image(image_id).expect("Image does not exist");
473 let extent = image.kind().extent();
474 framebuffer_width = min(framebuffer_width, extent.width);
475 framebuffer_height = min(framebuffer_height, extent.height);
476 framebuffer_layers = min(
477 framebuffer_layers,
478 node_image.range.layers.end - node_image.range.layers.start,
479 );
480 Ok(vec![unsafe {
481 factory
482 .device()
483 .create_image_view(
484 image.raw(),
485 rendy_core::hal::image::ViewKind::D2,
486 image.format(),
487 rendy_core::hal::format::Swizzle::NO,
488 rendy_core::hal::image::SubresourceRange {
489 levels: 0 .. 1,
493 ..node_image.range.clone()
494 }
495 )
496 .map_err(NodeBuildError::View)?
497 }])
498 },
499 Either::Right(RenderPassSurface) => {
500 log::trace!("Surface attachment");
501
502 let surface = surface.take().expect("Render pass should be configured with Surface instance if at least one subpass uses surface attachment");
503 let surface_extent = unsafe {
504 surface.extent(factory.physical()).unwrap_or(suggested_extent.expect("Must be set with surface"))
505 };
506
507 log::debug!("Surface extent {:#?}", surface_extent);
508
509 if !factory.surface_support(family.id(), &surface) {
510 log::warn!("Surface {:?} presentation is unsupported by family {:?} bound to the node", surface, family);
511 return Err(NodeBuildError::QueueFamily(family.id()));
512 }
513
514 let caps = factory.get_surface_capabilities(&surface);
515
516 let present_mode = match () {
517 _ if caps.present_modes.contains(PresentMode::FIFO) => PresentMode::FIFO,
518 _ if caps.present_modes.contains(PresentMode::MAILBOX) => PresentMode::MAILBOX,
519 _ if caps.present_modes.contains(PresentMode::RELAXED) => PresentMode::RELAXED,
520 _ if caps.present_modes.contains(PresentMode::IMMEDIATE) => PresentMode::IMMEDIATE,
521 _ => panic!("No known present modes found"),
522 };
523
524 let img_count_caps = caps.image_count;
525 let image_count = 3.min(*img_count_caps.end()).max(*img_count_caps.start());
526
527 let target = factory
528 .create_target(
529 surface,
530 surface_extent,
531 image_count,
532 present_mode,
533 surface_usage,
534 )
535 .map_err(NodeBuildError::Swapchain)?;
536
537 framebuffer_width = min(framebuffer_width, target.extent().width);
538 framebuffer_height = min(framebuffer_height, target.extent().height);
539 framebuffer_layers = min(
540 framebuffer_layers,
541 target.backbuffer()[0].layers(),
542 );
543
544 let views = target.backbuffer().iter().map(|image| unsafe {
545 factory
546 .device()
547 .create_image_view(
548 image.raw(),
549 rendy_core::hal::image::ViewKind::D2,
550 image.format(),
551 rendy_core::hal::format::Swizzle::NO,
552 rendy_core::hal::image::SubresourceRange {
553 aspects: image.format().surface_desc().aspects,
554 levels: 0 .. 1,
555 layers: 0 .. 1,
556 },
557 )
558 .map_err(NodeBuildError::View)
559 }).collect::<Result<Vec<_>, NodeBuildError>>()?;
560
561 node_target = Some(target);
562 Ok(views)
563 }
564 }
565 }).collect::<Result<Vec<_>, _>>()?
566 .into_iter().flatten().collect();
567
568 log::trace!("Configure render pass instance");
569
570 let render_pass: B::RenderPass = {
571 let pass_attachments: Vec<_> = attachments
572 .iter()
573 .map(|&attachment| {
574 let (format, clear, layout, samples) = match attachment {
575 Either::Left(image_id) => {
576 let node_image = find_attachment_node_image(image_id);
577 let image = ctx.get_image(image_id).expect("Image does not exist");
578 (
579 image.format(),
580 node_image.clear,
581 node_image.layout,
582 image.kind().num_samples(),
583 )
584 }
585 Either::Right(RenderPassSurface) => (
586 node_target
587 .as_ref()
588 .expect("Expect target created")
589 .backbuffer()[0]
590 .format(),
591 surface_clear,
592 rendy_core::hal::image::Layout::Present,
593 1,
594 ),
595 };
596
597 rendy_core::hal::pass::Attachment {
598 format: Some(format),
599 ops: rendy_core::hal::pass::AttachmentOps {
600 load: if clear.is_some() {
601 rendy_core::hal::pass::AttachmentLoadOp::Clear
602 } else {
603 rendy_core::hal::pass::AttachmentLoadOp::Load
604 },
605 store: rendy_core::hal::pass::AttachmentStoreOp::Store,
606 },
607 stencil_ops: rendy_core::hal::pass::AttachmentOps::DONT_CARE,
608 layouts: if clear.is_some() {
609 rendy_core::hal::image::Layout::Undefined..layout
610 } else {
611 layout..layout
612 },
613 samples,
614 }
615 })
616 .collect();
617
618 log::debug!("Attachments {:#?}", pass_attachments);
619
620 #[derive(Debug)]
621 struct OwningSubpassDesc {
622 inputs: Vec<(usize, Layout)>,
623 colors: Vec<(usize, Layout)>,
624 depth_stencil: Option<(usize, Layout)>,
625 }
626
627 let subpasses: Vec<_> = self
628 .subpasses
629 .iter()
630 .map(|subpass| OwningSubpassDesc {
631 inputs: subpass
632 .inputs
633 .iter()
634 .map(|&i| {
635 (
636 attachments.iter().position(|&a| a == i).unwrap(),
637 match i {
638 Either::Left(image_id) => {
639 find_attachment_node_image(image_id).layout
640 }
641 Either::Right(RenderPassSurface) => {
642 rendy_core::hal::image::Layout::ShaderReadOnlyOptimal
643 }
644 },
645 )
646 })
647 .collect(),
648 colors: subpass
649 .colors
650 .iter()
651 .map(|&c| {
652 (
653 attachments.iter().position(|&a| a == c).unwrap(),
654 match c {
655 Either::Left(image_id) => {
656 find_attachment_node_image(image_id).layout
657 }
658 Either::Right(RenderPassSurface) => {
659 rendy_core::hal::image::Layout::ColorAttachmentOptimal
660 }
661 },
662 )
663 })
664 .collect(),
665 depth_stencil: subpass.depth_stencil.map(|ds| {
666 (
667 attachments.iter().position(|&a| a == ds).unwrap(),
668 match ds {
669 Either::Left(image_id) => {
670 find_attachment_node_image(image_id).layout
671 }
672 Either::Right(RenderPassSurface) => {
673 rendy_core::hal::image::Layout::DepthStencilAttachmentOptimal
674 }
675 },
676 )
677 }),
678 })
679 .collect();
680
681 log::debug!("Subpasses {:#?}", subpasses);
682
683 let subpasses: Vec<_> = subpasses
684 .iter()
685 .map(|subpass| rendy_core::hal::pass::SubpassDesc {
686 inputs: &subpass.inputs[..],
687 colors: &subpass.colors[..],
688 depth_stencil: subpass.depth_stencil.as_ref(),
689 resolves: &[],
690 preserves: &[],
691 })
692 .collect();
693
694 let result = unsafe {
695 factory
696 .device()
697 .create_render_pass(pass_attachments, subpasses, {
698 assert_eq!(
699 self.subpasses.len(),
700 1,
701 "TODO: Implement subpass dependencies to allow more than one subpass"
702 );
703 std::iter::empty::<rendy_core::hal::pass::SubpassDependency>()
704 })
705 }
706 .unwrap();
707
708 log::trace!("RenderPass instance created");
709 result
710 };
711
712 log::trace!(
713 "Create {} framebuffers",
714 views.len() - attachments.len() + 1
715 );
716
717 let mut framebuffers = (attachments.len() - 1..views.len())
719 .map(|i| unsafe {
720 log::trace!(
721 "Create framebuffer for views {}..{} and {}",
722 0,
723 attachments.len() - 1,
724 i,
725 );
726 factory
727 .device()
728 .create_framebuffer(
729 &render_pass,
730 views[..attachments.len() - 1].iter().chain(Some(&views[i])),
731 rendy_core::hal::image::Extent {
732 width: framebuffer_width,
733 height: framebuffer_height,
734 depth: framebuffer_layers as u32, },
736 )
737 .map_err(NodeBuildError::OutOfMemory)
738 })
739 .collect::<Result<Vec<_>, _>>()?;
740
741 log::trace!("Collect clears for render pass");
742
743 let clears: Vec<_> = attachments
744 .iter()
745 .filter_map(|&a| match a {
746 Either::Left(image_id) => find_attachment_node_image(image_id).clear,
747 Either::Right(RenderPassSurface) => surface_clear,
748 })
749 .map(Into::into)
750 .collect();
751
752 let mut command_pool = factory
753 .create_command_pool(family)
754 .map_err(NodeBuildError::OutOfMemory)?
755 .with_capability()
756 .expect("Graph must specify family that supports `Graphics`");
757
758 let command_cirque = CommandCirque::new();
759
760 let acquire = if uses_pipeline_barriers::<B>(factory.device()) {
761 let (stages, barriers) = gfx_acquire_barriers(ctx, &buffers, &images);
762
763 if !barriers.is_empty() {
764 let initial = command_pool.allocate_buffers(1).pop().unwrap();
765 let mut recording = initial.begin(MultiShot(SimultaneousUse), ());
766 log::debug!("Acquire {:?} : {:#?}", stages, barriers);
767 unsafe {
768 recording.encoder().pipeline_barrier(
769 stages,
770 rendy_core::hal::memory::Dependencies::empty(),
771 barriers,
772 );
773 }
774 let (acquire_submit, acquire_buffer) = recording.finish().submit();
775 Some(BarriersCommands {
776 buffer: acquire_buffer,
777 submit: acquire_submit,
778 })
779 } else {
780 None
781 }
782 } else {
783 None
784 };
785
786 let release = if uses_pipeline_barriers::<B>(factory.device()) {
787 let (stages, barriers) = gfx_release_barriers(ctx, &buffers, &images);
788
789 if !barriers.is_empty() {
790 let initial = command_pool.allocate_buffers(1).pop().unwrap();
791 let mut recording = initial.begin(MultiShot(SimultaneousUse), ());
792 log::debug!("Release {:?} : {:#?}", stages, barriers);
793 unsafe {
794 recording.encoder().pipeline_barrier(
795 stages,
796 rendy_core::hal::memory::Dependencies::empty(),
797 barriers,
798 );
799 }
800 let (release_submit, release_buffer) = recording.finish().submit();
801 Some(BarriersCommands {
802 buffer: release_buffer,
803 submit: release_submit,
804 })
805 } else {
806 None
807 }
808 } else {
809 None
810 };
811
812 let subpasses = self
813 .subpasses
814 .into_iter()
815 .enumerate()
816 .map(|(index, subpass)| {
817 let subpass_colors = subpass.colors.len();
818 let subpass_depth = subpass.depth_stencil.is_some();
819
820 subpass
821 .groups
822 .into_iter()
823 .map(|group| {
824 assert_eq!(group.colors(), subpass_colors);
825 assert_eq!(group.depth(), subpass_depth);
826
827 let buffers: Vec<_> = group
828 .buffers()
829 .into_iter()
830 .map(|(id, _)| {
831 buffers
832 .iter()
833 .find(|b| b.id == id)
834 .expect("Transient buffer wasn't provided")
835 .clone()
836 })
837 .collect();
838 let images: Vec<_> = group
839 .images()
840 .into_iter()
841 .map(|(id, _)| {
842 images
843 .iter()
844 .find(|i| i.id == id)
845 .expect("Transient image wasn't provided")
846 .clone()
847 })
848 .collect();
849
850 group.build(
851 ctx,
852 factory,
853 QueueId {
854 family: family.id(),
855 index: queue,
856 },
857 aux,
858 framebuffer_width,
859 framebuffer_height,
860 rendy_core::hal::pass::Subpass {
861 index,
862 main_pass: &render_pass,
863 },
864 buffers,
865 images,
866 )
867 })
868 .collect::<Result<Vec<_>, _>>()
869 .map(|groups| SubpassNode { groups })
870 })
871 .collect::<Result<Vec<_>, _>>()
872 .map_err(NodeBuildError::Pipeline)?;
873
874 let node: Box<dyn DynNode<B, T>> = match node_target {
875 Some(target) => {
876 log::debug!("Construct RenderPassNodeWithSurface");
877 Box::new(RenderPassNodeWithSurface {
878 common: RenderPassNodeCommon {
879 subpasses,
880
881 framebuffer_width,
882 framebuffer_height,
883 _framebuffer_layers: framebuffer_layers,
884
885 render_pass,
886 views,
887 clears,
888
889 command_pool,
890 command_cirque,
891
892 acquire,
893 release,
894
895 relevant: relevant::Relevant,
896 },
897
898 per_image: framebuffers
899 .into_iter()
900 .map(|fb| PerImage {
901 framebuffer: fb,
902 acquire: factory.create_semaphore().unwrap(),
903 release: factory.create_semaphore().unwrap(),
904 index: 0,
905 })
906 .collect(),
907 free_acquire: factory.create_semaphore().unwrap(),
908 target,
909 })
910 }
911 None => {
912 log::debug!("Construct RenderPassNodeWithoutSurface");
913 Box::new(RenderPassNodeWithoutSurface {
914 common: RenderPassNodeCommon {
915 subpasses,
916
917 framebuffer_width,
918 framebuffer_height,
919 _framebuffer_layers: framebuffer_layers,
920
921 render_pass,
922 views,
923 clears,
924
925 command_pool,
926 command_cirque,
927
928 acquire,
929 release,
930
931 relevant: relevant::Relevant,
932 },
933 framebuffer: {
934 assert_eq!(framebuffers.len(), 1);
935 framebuffers.remove(0)
936 },
937 })
938 }
939 };
940
941 Ok(node)
942 }
943}
944
945struct SubpassNode<B: Backend, T: ?Sized> {
947 groups: Vec<Box<dyn RenderGroup<B, T>>>,
949}
950
951impl<B, T> std::fmt::Debug for SubpassNode<B, T>
952where
953 B: Backend,
954 T: ?Sized,
955{
956 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
957 fmt.debug_struct("SubpassNode")
958 .field("groups", &self.groups)
959 .finish()
960 }
961}
962
963struct BarriersCommands<B: Backend> {
964 submit: Submit<B, SimultaneousUse, SecondaryLevel>,
965 buffer: CommandBuffer<
966 B,
967 Graphics,
968 PendingState<ExecutableState<MultiShot<SimultaneousUse>>>,
969 SecondaryLevel,
970 IndividualReset,
971 >,
972}
973
974impl<B> std::fmt::Debug for BarriersCommands<B>
975where
976 B: Backend,
977{
978 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
979 fmt.debug_struct("BarriersCommands")
980 .field("submit", &self.submit)
981 .field("buffer", &self.buffer)
982 .finish()
983 }
984}
985
986struct RenderPassNodeCommon<B: Backend, T: ?Sized> {
987 subpasses: Vec<SubpassNode<B, T>>,
988
989 framebuffer_width: u32,
990 framebuffer_height: u32,
991 _framebuffer_layers: u16,
992
993 render_pass: B::RenderPass,
994 views: Vec<B::ImageView>,
995 clears: Vec<rendy_core::hal::command::ClearValue>,
996
997 command_pool: CommandPool<B, Graphics, IndividualReset>,
998 command_cirque: CommandCirque<B, Graphics>,
999
1000 acquire: Option<BarriersCommands<B>>,
1001 release: Option<BarriersCommands<B>>,
1002
1003 relevant: relevant::Relevant,
1004}
1005
1006impl<B, T> std::fmt::Debug for RenderPassNodeCommon<B, T>
1007where
1008 B: Backend,
1009 T: ?Sized,
1010{
1011 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1012 fmt.debug_struct("RenderPassNodeCommon")
1013 .field("subpasses", &self.subpasses)
1014 .field("framebuffer_width", &self.framebuffer_width)
1015 .field("framebuffer_height", &self.framebuffer_height)
1016 .field("_framebuffer_layers", &self._framebuffer_layers)
1017 .field("render_pass", &self.render_pass)
1018 .field("views", &self.views)
1019 .field("clears", &self.clears)
1020 .field("command_pool", &self.command_pool)
1021 .field("command_cirque", &self.command_cirque)
1022 .field("acquire", &self.acquire)
1023 .field("release", &self.release)
1024 .field("relevant", &self.relevant)
1025 .finish()
1026 }
1027}
1028
1029impl<B, T> RenderPassNodeCommon<B, T>
1030where
1031 B: Backend,
1032 T: ?Sized,
1033{
1034 unsafe fn dispose(mut self, factory: &mut Factory<B>, aux: &T) {
1035 self.relevant.dispose();
1036 for subpass in self.subpasses {
1037 for group in subpass.groups {
1038 group.dispose(factory, aux)
1039 }
1040 }
1041 let pool = &mut self.command_pool;
1042 self.command_cirque.dispose(|buffer| {
1043 buffer.either_with(
1044 &mut *pool,
1045 |pool, executable| pool.free_buffers(Some(executable)),
1046 |pool, pending| {
1047 let executable = pending.mark_complete();
1048 pool.free_buffers(Some(executable))
1049 },
1050 );
1051 });
1052 if let Some(BarriersCommands { submit, buffer }) = self.acquire.take() {
1053 drop(submit);
1054 let executable = buffer.mark_complete();
1055 pool.free_buffers(Some(executable));
1056 }
1057 if let Some(BarriersCommands { submit, buffer }) = self.release.take() {
1058 drop(submit);
1059 let executable = buffer.mark_complete();
1060 pool.free_buffers(Some(executable));
1061 }
1062 factory.destroy_command_pool(self.command_pool.with_queue_type());
1063
1064 for view in self.views {
1065 factory.device().destroy_image_view(view);
1066 }
1067 factory.device().destroy_render_pass(self.render_pass);
1068 }
1069}
1070
1071#[derive(Debug)]
1072struct PerImage<B: Backend> {
1073 framebuffer: B::Framebuffer,
1074 acquire: B::Semaphore,
1075 release: B::Semaphore,
1076 index: usize,
1077}
1078
1079struct RenderPassNodeWithSurface<B: Backend, T: ?Sized> {
1080 common: RenderPassNodeCommon<B, T>,
1081 per_image: Vec<PerImage<B>>,
1082 free_acquire: B::Semaphore,
1083 target: Target<B>,
1084}
1085
1086impl<B, T> std::fmt::Debug for RenderPassNodeWithSurface<B, T>
1087where
1088 B: Backend,
1089 T: ?Sized,
1090{
1091 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1092 fmt.debug_struct("RenderPassNodeWithSurface")
1093 .field("common", &self.common)
1094 .field("per_image", &self.per_image)
1095 .field("free_acquire", &self.free_acquire)
1096 .field("target", &self.target)
1097 .finish()
1098 }
1099}
1100
1101impl<B, T> DynNode<B, T> for RenderPassNodeWithSurface<B, T>
1102where
1103 B: Backend,
1104 T: ?Sized,
1105{
1106 unsafe fn run<'a>(
1107 &mut self,
1108 _ctx: &GraphContext<B>,
1109 factory: &Factory<B>,
1110 queue: &mut Queue<B>,
1111 aux: &T,
1112 frames: &Frames<B>,
1113 waits: &[(&'a B::Semaphore, rendy_core::hal::pso::PipelineStage)],
1114 signals: &[&'a B::Semaphore],
1115 fence: Option<&mut Fence<B>>,
1116 ) {
1117 let RenderPassNodeWithSurface {
1118 common:
1119 RenderPassNodeCommon {
1120 subpasses,
1121
1122 framebuffer_width,
1123 framebuffer_height,
1124
1125 render_pass,
1126 clears,
1127
1128 command_cirque,
1129 command_pool,
1130
1131 acquire,
1132 release,
1133 ..
1134 },
1135 target,
1136 free_acquire,
1137 per_image,
1138 } = self;
1139
1140 let next = match target.next_image(&free_acquire) {
1141 Ok(next) => {
1142 log::trace!("Presentable image acquired: {:#?}", next);
1143 std::mem::swap(&mut per_image[next[0] as usize].acquire, free_acquire);
1144 Some(next)
1145 }
1146 Err(err) => {
1147 log::debug!("Swapchain acquisition error: {:#?}", err);
1148 None
1149 }
1150 };
1151
1152 let submit = command_cirque.encode(frames, command_pool, |mut cbuf| {
1153 let index = cbuf.index();
1154
1155 if let Some(next) = &next {
1156 let ref mut for_image = per_image[next[0] as usize];
1157
1158 let force_record = subpasses.iter_mut().enumerate().fold(
1159 false,
1160 |force_record, (subpass_index, subpass)| {
1161 subpass
1162 .groups
1163 .iter_mut()
1164 .fold(force_record, |force_record, group| {
1165 group
1166 .prepare(
1167 factory,
1168 queue.id(),
1169 index,
1170 rendy_core::hal::pass::Subpass {
1171 index: subpass_index,
1172 main_pass: &render_pass,
1173 },
1174 aux,
1175 )
1176 .force_record()
1177 || force_record
1178 })
1179 },
1180 );
1181
1182 if force_record || for_image.index != index {
1183 for_image.index = index;
1184 cbuf = CirqueRef::Initial(cbuf.or_reset(|cbuf| cbuf.reset()));
1185 }
1186 }
1187
1188 cbuf.or_init(|cbuf| {
1189 let mut cbuf = cbuf.begin(MultiShot(NoSimultaneousUse), ());
1190 let mut encoder = cbuf.encoder();
1191
1192 if let Some(barriers) = &acquire {
1193 encoder.execute_commands(std::iter::once(&barriers.submit));
1194 }
1195
1196 if let Some(next) = &next {
1197 let ref mut for_image = per_image[next[0] as usize];
1198
1199 let area = rendy_core::hal::pso::Rect {
1200 x: 0,
1201 y: 0,
1202 w: *framebuffer_width as _,
1203 h: *framebuffer_height as _,
1204 };
1205
1206 let mut pass_encoder = encoder.begin_render_pass_inline(
1207 &render_pass,
1208 &for_image.framebuffer,
1209 area,
1210 &clears,
1211 );
1212
1213 subpasses
1214 .iter_mut()
1215 .enumerate()
1216 .for_each(|(subpass_index, subpass)| {
1217 subpass.groups.iter_mut().for_each(|group| {
1218 group.draw_inline(
1219 pass_encoder.reborrow(),
1220 index,
1221 rendy_core::hal::pass::Subpass {
1222 index: subpass_index,
1223 main_pass: &render_pass,
1224 },
1225 aux,
1226 )
1227 })
1228 });
1229
1230 drop(pass_encoder);
1231 }
1232
1233 if let Some(barriers) = &release {
1234 encoder.execute_commands(std::iter::once(&barriers.submit));
1235 }
1236 cbuf.finish()
1237 })
1238 });
1239
1240 log::trace!("Submit render pass");
1241
1242 queue.submit(
1243 Some(
1244 Submission::new()
1245 .submits(Some(submit))
1246 .wait(waits.iter().cloned().chain(next.as_ref().map(|n| {
1247 (
1248 &per_image[n[0] as usize].acquire,
1249 rendy_core::hal::pso::PipelineStage::TOP_OF_PIPE,
1250 )
1251 })))
1252 .signal(
1253 signals
1254 .iter()
1255 .cloned()
1256 .chain(next.as_ref().map(|n| (&per_image[n[0] as usize].release))),
1257 ),
1258 ),
1259 fence,
1260 );
1261
1262 if let Some(next) = next {
1263 log::trace!("Present");
1264 let ref mut for_image = per_image[next[0] as usize];
1265 if let Err(err) = next.present(queue.raw(), Some(&for_image.release)) {
1266 log::debug!("Swapchain presentation error: {:#?}", err);
1267 }
1268 }
1269 }
1270
1271 unsafe fn dispose(self: Box<Self>, factory: &mut Factory<B>, aux: &T) {
1272 for per_image in self.per_image {
1273 factory.device().destroy_framebuffer(per_image.framebuffer);
1274 factory.destroy_semaphore(per_image.acquire);
1275 factory.destroy_semaphore(per_image.release);
1276 }
1277 self.common.dispose(factory, aux);
1278 factory.destroy_surface(factory.destroy_target(self.target));
1279 }
1280}
1281
1282struct RenderPassNodeWithoutSurface<B: Backend, T: ?Sized> {
1283 common: RenderPassNodeCommon<B, T>,
1284 framebuffer: B::Framebuffer,
1285}
1286
1287impl<B, T> std::fmt::Debug for RenderPassNodeWithoutSurface<B, T>
1288where
1289 B: Backend,
1290 T: ?Sized,
1291{
1292 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1293 fmt.debug_struct("RenderPassNodeWithoutSurface")
1294 .field("common", &self.common)
1295 .field("framebuffer", &self.framebuffer)
1296 .finish()
1297 }
1298}
1299
1300impl<B, T> DynNode<B, T> for RenderPassNodeWithoutSurface<B, T>
1301where
1302 B: Backend,
1303 T: ?Sized,
1304{
1305 unsafe fn run<'a>(
1306 &mut self,
1307 _ctx: &GraphContext<B>,
1308 factory: &Factory<B>,
1309 queue: &mut Queue<B>,
1310 aux: &T,
1311 frames: &Frames<B>,
1312 waits: &[(&'a B::Semaphore, rendy_core::hal::pso::PipelineStage)],
1313 signals: &[&'a B::Semaphore],
1314 fence: Option<&mut Fence<B>>,
1315 ) {
1316 let RenderPassNodeWithoutSurface {
1317 common:
1318 RenderPassNodeCommon {
1319 subpasses,
1320
1321 framebuffer_width,
1322 framebuffer_height,
1323
1324 render_pass,
1325 clears,
1326
1327 command_cirque,
1328 command_pool,
1329
1330 acquire,
1331 release,
1332 ..
1333 },
1334 framebuffer,
1335 } = self;
1336
1337 let submit = command_cirque.encode(frames, command_pool, |mut cbuf| {
1338 let index = cbuf.index();
1339
1340 let force_record = subpasses.iter_mut().enumerate().fold(
1341 false,
1342 |force_record, (subpass_index, subpass)| {
1343 subpass
1344 .groups
1345 .iter_mut()
1346 .fold(force_record, |force_record, group| {
1347 group
1348 .prepare(
1349 factory,
1350 queue.id(),
1351 index,
1352 rendy_core::hal::pass::Subpass {
1353 index: subpass_index,
1354 main_pass: &render_pass,
1355 },
1356 aux,
1357 )
1358 .force_record()
1359 || force_record
1360 })
1361 },
1362 );
1363
1364 if force_record {
1365 cbuf = CirqueRef::Initial(cbuf.or_reset(|cbuf| cbuf.reset()));
1366 }
1367
1368 cbuf.or_init(|cbuf| {
1369 let mut cbuf = cbuf.begin(MultiShot(NoSimultaneousUse), ());
1370 let mut encoder = cbuf.encoder();
1371
1372 if let Some(barriers) = &acquire {
1373 encoder.execute_commands(std::iter::once(&barriers.submit));
1374 }
1375
1376 let area = rendy_core::hal::pso::Rect {
1377 x: 0,
1378 y: 0,
1379 w: *framebuffer_width as _,
1380 h: *framebuffer_height as _,
1381 };
1382
1383 let mut pass_encoder =
1384 encoder.begin_render_pass_inline(&render_pass, framebuffer, area, &clears);
1385
1386 subpasses
1387 .iter_mut()
1388 .enumerate()
1389 .for_each(|(subpass_index, subpass)| {
1390 subpass.groups.iter_mut().for_each(|group| {
1391 group.draw_inline(
1392 pass_encoder.reborrow(),
1393 index,
1394 rendy_core::hal::pass::Subpass {
1395 index: subpass_index,
1396 main_pass: &render_pass,
1397 },
1398 aux,
1399 )
1400 })
1401 });
1402
1403 drop(pass_encoder);
1404
1405 if let Some(barriers) = &release {
1406 encoder.execute_commands(std::iter::once(&barriers.submit));
1407 }
1408 cbuf.finish()
1409 })
1410 });
1411
1412 queue.submit(
1413 Some(
1414 Submission::new()
1415 .submits(Some(submit))
1416 .wait(waits.iter().cloned())
1417 .signal(signals.iter().cloned()),
1418 ),
1419 fence,
1420 );
1421 }
1422
1423 unsafe fn dispose(self: Box<Self>, factory: &mut Factory<B>, aux: &T) {
1424 self.common.dispose(factory, aux);
1425 factory.device().destroy_framebuffer(self.framebuffer);
1426 }
1427}
1428
1429fn common_layout(acc: Layout, layout: Layout) -> Layout {
1430 match (acc, layout) {
1431 (Layout::Undefined, layout) => layout,
1432 (left, right) if left == right => left,
1433 (Layout::DepthStencilReadOnlyOptimal, Layout::DepthStencilAttachmentOptimal) => {
1434 Layout::DepthStencilAttachmentOptimal
1435 }
1436 (Layout::DepthStencilAttachmentOptimal, Layout::DepthStencilReadOnlyOptimal) => {
1437 Layout::DepthStencilAttachmentOptimal
1438 }
1439 (_, _) => Layout::General,
1440 }
1441}