Skip to main content

duku/pipeline/
render_pass.rs

1// Oliver Berzs
2// https://github.com/oberzs/duku
3
4// RenderPass - struct that structures a rendering pass
5
6use std::ptr;
7
8use super::Attachment;
9use super::Clear;
10use super::ShaderConfig;
11use super::Store;
12use crate::device::Device;
13use crate::image::Format;
14use crate::image::ImageLayout;
15use crate::image::Msaa;
16use crate::vk;
17
18pub(crate) struct RenderPass {
19    handle: vk::RenderPass,
20    attachments: Vec<Attachment>,
21}
22
23impl RenderPass {
24    pub(crate) fn new(device: &Device, config: ShaderConfig, present: bool) -> Self {
25        let multisampled = config.msaa != Msaa::Disabled;
26        let only_depth = config.outputs == 0;
27
28        let mut attachment_descriptions = vec![];
29        let mut attachments = vec![];
30
31        // add depth attachment if needed
32        let layout = if only_depth {
33            ImageLayout::ShaderDepth
34        } else {
35            ImageLayout::Depth
36        };
37
38        let a = Attachment::new(
39            attachments.len() as u32,
40            layout,
41            Format::Depth,
42            config.msaa,
43            Clear::Enabled,
44            Store::from(only_depth),
45        );
46
47        let depth_attachment = a.reference();
48        attachment_descriptions.push(a.description());
49        attachments.push(a);
50
51        // add color and resolve attachments
52        let mut color_attachments = vec![];
53        let mut resolve_attachments = vec![];
54        for _ in 0..config.outputs {
55            // base color attachment
56            let layout = if present {
57                ImageLayout::Present
58            } else {
59                ImageLayout::ShaderColor
60            };
61
62            let a = Attachment::new(
63                attachments.len() as u32,
64                layout,
65                Format::Bgra,
66                Msaa::Disabled,
67                Clear::from(!multisampled),
68                Store::Enabled,
69            );
70
71            if multisampled {
72                resolve_attachments.push(a.reference());
73            } else {
74                color_attachments.push(a.reference());
75            }
76            attachment_descriptions.push(a.description());
77            attachments.push(a);
78
79            // color multisampled attachment
80            if multisampled {
81                let a_msaa = Attachment::new(
82                    attachments.len() as u32,
83                    ImageLayout::Color,
84                    Format::Bgra,
85                    config.msaa,
86                    Clear::Enabled,
87                    Store::Disabled,
88                );
89
90                color_attachments.push(a_msaa.reference());
91                attachment_descriptions.push(a_msaa.description());
92                attachments.push(a_msaa);
93            }
94        }
95
96        // create subpass dependency
97        let dependencies = if only_depth {
98            // depth pass
99            [
100                // start of render pass dependency
101                vk::SubpassDependency {
102                    src_subpass: vk::SUBPASS_EXTERNAL,
103                    dst_subpass: 0,
104                    src_stage_mask: vk::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
105                    dst_stage_mask: vk::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
106                    src_access_mask: 0,
107                    dst_access_mask: vk::ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
108                    dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
109                },
110                // end of render pass dependency
111                vk::SubpassDependency {
112                    src_subpass: 0,
113                    dst_subpass: vk::SUBPASS_EXTERNAL,
114                    src_stage_mask: vk::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
115                    dst_stage_mask: vk::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
116                    src_access_mask: vk::ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
117                    dst_access_mask: 0,
118                    dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
119                },
120            ]
121        } else {
122            // color pass
123            [
124                // start of render pass dependency
125                vk::SubpassDependency {
126                    src_subpass: vk::SUBPASS_EXTERNAL,
127                    dst_subpass: 0,
128                    src_stage_mask: vk::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
129                    dst_stage_mask: vk::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
130                    src_access_mask: 0,
131                    dst_access_mask: vk::ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
132                    dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
133                },
134                // end of render pass dependency
135                vk::SubpassDependency {
136                    src_subpass: 0,
137                    dst_subpass: vk::SUBPASS_EXTERNAL,
138                    src_stage_mask: vk::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
139                    dst_stage_mask: vk::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
140                    src_access_mask: vk::ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
141                    dst_access_mask: 0,
142                    dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
143                },
144            ]
145        };
146
147        // create render pass
148        let mut subpass = [vk::SubpassDescription {
149            flags: 0,
150            pipeline_bind_point: vk::PIPELINE_BIND_POINT_GRAPHICS,
151            input_attachment_count: 0,
152            p_input_attachments: ptr::null(),
153            color_attachment_count: 0,
154            p_color_attachments: ptr::null(),
155            p_resolve_attachments: ptr::null(),
156            p_depth_stencil_attachment: &depth_attachment,
157            preserve_attachment_count: 0,
158            p_preserve_attachments: ptr::null(),
159        }];
160
161        if !color_attachments.is_empty() {
162            subpass[0].color_attachment_count = color_attachments.len() as u32;
163            subpass[0].p_color_attachments = color_attachments.as_ptr();
164        }
165        if !resolve_attachments.is_empty() {
166            subpass[0].p_resolve_attachments = resolve_attachments.as_ptr();
167        }
168
169        let info = vk::RenderPassCreateInfo {
170            s_type: vk::STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
171            p_next: ptr::null(),
172            flags: 0,
173            attachment_count: attachment_descriptions.len() as u32,
174            p_attachments: attachment_descriptions.as_ptr(),
175            subpass_count: subpass.len() as u32,
176            p_subpasses: subpass.as_ptr(),
177            dependency_count: dependencies.len() as u32,
178            p_dependencies: dependencies.as_ptr(),
179        };
180
181        let handle = device.create_render_pass(&info);
182
183        Self {
184            attachments,
185            handle,
186        }
187    }
188
189    pub(crate) fn destroy(&self, device: &Device) {
190        device.destroy_render_pass(self.handle);
191    }
192
193    pub(crate) fn attachments(&self) -> impl Iterator<Item = &Attachment> {
194        self.attachments.iter()
195    }
196
197    pub(crate) const fn handle(&self) -> vk::RenderPass {
198        self.handle
199    }
200}