screen_13/driver/
render_pass.rs

1//! Render pass related types.
2
3use {
4    super::{DepthStencilMode, DriverError, GraphicPipeline, SampleCount, device::Device},
5    ash::vk,
6    log::{trace, warn},
7    std::{
8        collections::{HashMap, hash_map::Entry},
9        ops::Deref,
10        sync::Arc,
11        thread::panicking,
12    },
13};
14
15#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
16pub(crate) struct AttachmentInfo {
17    pub flags: vk::AttachmentDescriptionFlags,
18    pub fmt: vk::Format,
19    pub sample_count: SampleCount,
20    pub load_op: vk::AttachmentLoadOp,
21    pub store_op: vk::AttachmentStoreOp,
22    pub stencil_load_op: vk::AttachmentLoadOp,
23    pub stencil_store_op: vk::AttachmentStoreOp,
24    pub initial_layout: vk::ImageLayout,
25    pub final_layout: vk::ImageLayout,
26}
27
28impl From<AttachmentInfo> for vk::AttachmentDescription2<'_> {
29    fn from(value: AttachmentInfo) -> Self {
30        vk::AttachmentDescription2::default()
31            .flags(value.flags)
32            .format(value.fmt)
33            .samples(value.sample_count.into())
34            .load_op(value.load_op)
35            .store_op(value.store_op)
36            .stencil_load_op(value.stencil_load_op)
37            .stencil_store_op(value.stencil_store_op)
38            .initial_layout(value.initial_layout)
39            .final_layout(value.final_layout)
40    }
41}
42
43impl Default for AttachmentInfo {
44    fn default() -> Self {
45        AttachmentInfo {
46            flags: vk::AttachmentDescriptionFlags::MAY_ALIAS,
47            fmt: vk::Format::UNDEFINED,
48            sample_count: SampleCount::Type1,
49            initial_layout: vk::ImageLayout::UNDEFINED,
50            load_op: vk::AttachmentLoadOp::DONT_CARE,
51            stencil_load_op: vk::AttachmentLoadOp::DONT_CARE,
52            store_op: vk::AttachmentStoreOp::DONT_CARE,
53            stencil_store_op: vk::AttachmentStoreOp::DONT_CARE,
54            final_layout: vk::ImageLayout::UNDEFINED,
55        }
56    }
57}
58
59#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
60pub(crate) struct AttachmentRef {
61    pub attachment: u32,
62    pub aspect_mask: vk::ImageAspectFlags,
63    pub layout: vk::ImageLayout,
64}
65
66impl From<AttachmentRef> for vk::AttachmentReference2<'_> {
67    fn from(attachment_ref: AttachmentRef) -> Self {
68        vk::AttachmentReference2::default()
69            .attachment(attachment_ref.attachment)
70            .aspect_mask(attachment_ref.aspect_mask)
71            .layout(attachment_ref.layout)
72    }
73}
74
75#[derive(Clone, Debug, Eq, Hash, PartialEq)]
76pub(crate) struct FramebufferAttachmentImageInfo {
77    pub flags: vk::ImageCreateFlags,
78    pub usage: vk::ImageUsageFlags,
79    pub width: u32,
80    pub height: u32,
81    pub layer_count: u32,
82    pub view_formats: Vec<vk::Format>,
83}
84
85#[derive(Clone, Debug, Eq, Hash, PartialEq)]
86pub(crate) struct FramebufferInfo {
87    pub attachments: Vec<FramebufferAttachmentImageInfo>,
88}
89
90#[derive(Debug, Eq, Hash, PartialEq)]
91struct GraphicPipelineKey {
92    depth_stencil: Option<DepthStencilMode>,
93    layout: vk::PipelineLayout,
94    shader_modules: Vec<vk::ShaderModule>,
95    subpass_idx: u32,
96}
97
98#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
99pub(crate) struct RenderPassInfo {
100    pub attachments: Vec<AttachmentInfo>,
101    pub subpasses: Vec<SubpassInfo>,
102    pub dependencies: Vec<SubpassDependency>,
103}
104
105#[derive(Debug)]
106pub(crate) struct RenderPass {
107    device: Arc<Device>,
108    framebuffers: HashMap<FramebufferInfo, vk::Framebuffer>,
109    graphic_pipelines: HashMap<GraphicPipelineKey, vk::Pipeline>,
110    pub info: RenderPassInfo,
111    render_pass: vk::RenderPass,
112}
113
114impl RenderPass {
115    #[profiling::function]
116    pub fn create(device: &Arc<Device>, info: RenderPassInfo) -> Result<Self, DriverError> {
117        //trace!("create: \n{:#?}", &info);
118        trace!("create");
119
120        let device = Arc::clone(device);
121        let attachments = info
122            .attachments
123            .iter()
124            .copied()
125            .map(Into::into)
126            .collect::<Box<[_]>>();
127        let correlated_view_masks = if info.subpasses.iter().any(|subpass| subpass.view_mask != 0) {
128            {
129                info.subpasses
130                    .iter()
131                    .map(|subpass| subpass.correlated_view_mask)
132                    .collect::<Box<_>>()
133            }
134        } else {
135            Default::default()
136        };
137        let dependencies = info
138            .dependencies
139            .iter()
140            .copied()
141            .map(Into::into)
142            .collect::<Box<[_]>>();
143
144        let subpass_attachments = info
145            .subpasses
146            .iter()
147            .flat_map(|subpass| {
148                subpass
149                    .color_attachments
150                    .iter()
151                    .chain(subpass.input_attachments.iter())
152                    .chain(subpass.color_resolve_attachments.iter())
153                    .chain(subpass.depth_stencil_attachment.iter())
154                    .chain(
155                        subpass
156                            .depth_stencil_resolve_attachment
157                            .as_ref()
158                            .map(|(resolve_attachment, _, _)| resolve_attachment)
159                            .into_iter(),
160                    )
161                    .copied()
162                    .map(AttachmentRef::into)
163            })
164            .collect::<Box<[vk::AttachmentReference2]>>();
165        let mut subpass_depth_stencil_resolves = info
166            .subpasses
167            .iter()
168            .map(|subpass| {
169                subpass.depth_stencil_resolve_attachment.map(
170                    |(_, depth_resolve_mode, stencil_resolve_mode)| {
171                        vk::SubpassDescriptionDepthStencilResolve::default()
172                            .depth_stencil_resolve_attachment(subpass_attachments.last().unwrap())
173                            .depth_resolve_mode(
174                                depth_resolve_mode.map(Into::into).unwrap_or_default(),
175                            )
176                            .stencil_resolve_mode(
177                                stencil_resolve_mode.map(Into::into).unwrap_or_default(),
178                            )
179                    },
180                )
181            })
182            .collect::<Box<_>>();
183        let mut subpasses = Vec::with_capacity(info.subpasses.len());
184
185        let mut base_idx = 0;
186        for (subpass, depth_stencil_resolve) in info
187            .subpasses
188            .iter()
189            .zip(subpass_depth_stencil_resolves.iter_mut())
190        {
191            let mut desc = vk::SubpassDescription2::default()
192                .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS);
193
194            debug_assert_eq!(
195                subpass.color_attachments.len(),
196                subpass.color_resolve_attachments.len()
197            );
198
199            let color_idx = base_idx;
200            let input_idx = color_idx + subpass.color_attachments.len();
201            let color_resolve_idx = input_idx + subpass.input_attachments.len();
202            let depth_stencil_idx = color_resolve_idx + subpass.color_resolve_attachments.len();
203            let depth_stencil_resolve_idx =
204                depth_stencil_idx + subpass.depth_stencil_attachment.is_some() as usize;
205            base_idx = depth_stencil_resolve_idx
206                + subpass.depth_stencil_resolve_attachment.is_some() as usize;
207
208            if subpass.depth_stencil_attachment.is_some() {
209                desc = desc.depth_stencil_attachment(&subpass_attachments[depth_stencil_idx]);
210            }
211
212            if let Some(depth_stencil_resolve) = depth_stencil_resolve {
213                desc = desc.push_next(depth_stencil_resolve);
214            }
215
216            subpasses.push(
217                desc.color_attachments(&subpass_attachments[color_idx..input_idx])
218                    .input_attachments(&subpass_attachments[input_idx..color_resolve_idx])
219                    .resolve_attachments(&subpass_attachments[color_resolve_idx..depth_stencil_idx])
220                    .preserve_attachments(&subpass.preserve_attachments)
221                    .view_mask(subpass.view_mask),
222            );
223        }
224
225        let render_pass = unsafe {
226            device
227                .create_render_pass2(
228                    &vk::RenderPassCreateInfo2::default()
229                        .attachments(&attachments)
230                        .correlated_view_masks(&correlated_view_masks)
231                        .dependencies(&dependencies)
232                        .subpasses(&subpasses),
233                    None,
234                )
235                .map_err(|err| {
236                    warn!("{err}");
237
238                    DriverError::Unsupported
239                })?
240        };
241
242        Ok(Self {
243            info,
244            device,
245            framebuffers: Default::default(),
246            graphic_pipelines: Default::default(),
247            render_pass,
248        })
249    }
250
251    #[profiling::function]
252    pub fn framebuffer(
253        this: &mut Self,
254        info: FramebufferInfo,
255    ) -> Result<vk::Framebuffer, DriverError> {
256        debug_assert!(!info.attachments.is_empty());
257
258        let entry = this.framebuffers.entry(info);
259        if let Entry::Occupied(entry) = entry {
260            return Ok(*entry.get());
261        }
262
263        let entry = match entry {
264            Entry::Vacant(entry) => entry,
265            _ => unreachable!(),
266        };
267
268        let key = entry.key();
269        let layers = key
270            .attachments
271            .iter()
272            .map(|attachment| attachment.layer_count)
273            .max()
274            .unwrap_or(1);
275        let attachments = key
276            .attachments
277            .iter()
278            .map(|attachment| {
279                vk::FramebufferAttachmentImageInfo::default()
280                    .flags(attachment.flags)
281                    .width(attachment.width)
282                    .height(attachment.height)
283                    .layer_count(attachment.layer_count)
284                    .usage(attachment.usage)
285                    .view_formats(&attachment.view_formats)
286            })
287            .collect::<Box<[_]>>();
288        let mut imageless_info =
289            vk::FramebufferAttachmentsCreateInfoKHR::default().attachment_image_infos(&attachments);
290        let mut create_info = vk::FramebufferCreateInfo::default()
291            .flags(vk::FramebufferCreateFlags::IMAGELESS)
292            .render_pass(this.render_pass)
293            .width(attachments[0].width)
294            .height(attachments[0].height)
295            .layers(layers)
296            .push_next(&mut imageless_info);
297        create_info.attachment_count = this.info.attachments.len() as _;
298
299        let framebuffer = unsafe {
300            this.device
301                .create_framebuffer(&create_info, None)
302                .map_err(|err| {
303                    warn!("{err}");
304
305                    DriverError::Unsupported
306                })?
307        };
308
309        entry.insert(framebuffer);
310
311        Ok(framebuffer)
312    }
313
314    #[profiling::function]
315    pub fn graphic_pipeline(
316        this: &mut Self,
317        pipeline: &Arc<GraphicPipeline>,
318        depth_stencil: Option<DepthStencilMode>,
319        subpass_idx: u32,
320    ) -> Result<vk::Pipeline, DriverError> {
321        use std::slice::from_ref;
322
323        let entry = this.graphic_pipelines.entry(GraphicPipelineKey {
324            depth_stencil,
325            layout: pipeline.layout,
326            shader_modules: pipeline.shader_modules.clone(),
327            subpass_idx,
328        });
329        if let Entry::Occupied(entry) = entry {
330            return Ok(*entry.get());
331        }
332
333        let entry = match entry {
334            Entry::Vacant(entry) => entry,
335            _ => unreachable!(),
336        };
337
338        let color_blend_attachment_states = this.info.subpasses[subpass_idx as usize]
339            .color_attachments
340            .iter()
341            .map(|_| pipeline.info.blend.into())
342            .collect::<Box<[_]>>();
343        let color_blend_state = vk::PipelineColorBlendStateCreateInfo::default()
344            .attachments(&color_blend_attachment_states);
345        let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
346        let dynamic_state =
347            vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
348        let multisample_state = vk::PipelineMultisampleStateCreateInfo::default()
349            .alpha_to_coverage_enable(pipeline.state.multisample.alpha_to_coverage_enable)
350            .alpha_to_one_enable(pipeline.state.multisample.alpha_to_one_enable)
351            .flags(pipeline.state.multisample.flags)
352            .min_sample_shading(pipeline.state.multisample.min_sample_shading)
353            .rasterization_samples(pipeline.state.multisample.rasterization_samples.into())
354            .sample_shading_enable(pipeline.state.multisample.sample_shading_enable)
355            .sample_mask(&pipeline.state.multisample.sample_mask);
356        let specializations = pipeline
357            .state
358            .stages
359            .iter()
360            .map(|stage| {
361                stage
362                    .specialization_info
363                    .as_ref()
364                    .map(|specialization_info| {
365                        vk::SpecializationInfo::default()
366                            .map_entries(&specialization_info.map_entries)
367                            .data(&specialization_info.data)
368                    })
369            })
370            .collect::<Box<_>>();
371        let stages = pipeline
372            .state
373            .stages
374            .iter()
375            .zip(specializations.iter())
376            .map(|(stage, specialization)| {
377                let mut info = vk::PipelineShaderStageCreateInfo::default()
378                    .module(stage.module)
379                    .name(&stage.name)
380                    .stage(stage.flags);
381
382                if let Some(specialization) = specialization {
383                    info = info.specialization_info(specialization);
384                }
385
386                info
387            })
388            .collect::<Box<[_]>>();
389        let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::default()
390            .vertex_attribute_descriptions(
391                &pipeline.state.vertex_input.vertex_attribute_descriptions,
392            )
393            .vertex_binding_descriptions(&pipeline.state.vertex_input.vertex_binding_descriptions);
394        let viewport_state = vk::PipelineViewportStateCreateInfo::default()
395            .viewport_count(1)
396            .scissor_count(1);
397        let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo {
398            topology: pipeline.info.topology,
399            ..Default::default()
400        };
401        let depth_stencil = depth_stencil.map(Into::into).unwrap_or_default();
402        let rasterization_state = vk::PipelineRasterizationStateCreateInfo {
403            front_face: pipeline.info.front_face,
404            line_width: 1.0,
405            polygon_mode: pipeline.info.polygon_mode,
406            cull_mode: pipeline.info.cull_mode,
407            ..Default::default()
408        };
409        let graphic_pipeline_info = vk::GraphicsPipelineCreateInfo::default()
410            .color_blend_state(&color_blend_state)
411            .depth_stencil_state(&depth_stencil)
412            .dynamic_state(&dynamic_state)
413            .input_assembly_state(&input_assembly_state)
414            .layout(pipeline.state.layout)
415            .multisample_state(&multisample_state)
416            .rasterization_state(&rasterization_state)
417            .render_pass(this.render_pass)
418            .stages(&stages)
419            .subpass(subpass_idx)
420            .vertex_input_state(&vertex_input_state)
421            .viewport_state(&viewport_state);
422
423        let pipeline = unsafe {
424            this.device.create_graphics_pipelines(
425                Device::pipeline_cache(&this.device),
426                from_ref(&graphic_pipeline_info),
427                None,
428            )
429        }
430        .map_err(|(_, err)| {
431            warn!(
432                "create_graphics_pipelines: {err}\n{:#?}",
433                graphic_pipeline_info
434            );
435
436            DriverError::Unsupported
437        })?[0];
438
439        entry.insert(pipeline);
440
441        Ok(pipeline)
442    }
443}
444
445impl Deref for RenderPass {
446    type Target = vk::RenderPass;
447
448    fn deref(&self) -> &Self::Target {
449        &self.render_pass
450    }
451}
452
453impl Drop for RenderPass {
454    #[profiling::function]
455    fn drop(&mut self) {
456        if panicking() {
457            return;
458        }
459
460        unsafe {
461            for (_, framebuffer) in self.framebuffers.drain() {
462                self.device.destroy_framebuffer(framebuffer, None);
463            }
464
465            for (_, pipeline) in self.graphic_pipelines.drain() {
466                self.device.destroy_pipeline(pipeline, None);
467            }
468
469            self.device.destroy_render_pass(self.render_pass, None);
470        }
471    }
472}
473
474/// Specifying depth and stencil resolve modes.
475#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
476pub enum ResolveMode {
477    /// The result of the resolve operation is the average of the sample values.
478    Average,
479
480    /// The result of the resolve operation is the maximum of the sample values.
481    Maximum,
482
483    /// The result of the resolve operation is the minimum of the sample values.
484    Minimum,
485
486    /// The result of the resolve operation is equal to the value of sample `0`.
487    SampleZero,
488}
489
490impl From<ResolveMode> for vk::ResolveModeFlags {
491    fn from(mode: ResolveMode) -> Self {
492        match mode {
493            ResolveMode::Average => vk::ResolveModeFlags::AVERAGE,
494            ResolveMode::Maximum => vk::ResolveModeFlags::MAX,
495            ResolveMode::Minimum => vk::ResolveModeFlags::MIN,
496            ResolveMode::SampleZero => vk::ResolveModeFlags::SAMPLE_ZERO,
497        }
498    }
499}
500
501#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
502pub(crate) struct SubpassDependency {
503    pub src_subpass: u32,
504    pub dst_subpass: u32,
505    pub src_stage_mask: vk::PipelineStageFlags,
506    pub dst_stage_mask: vk::PipelineStageFlags,
507    pub src_access_mask: vk::AccessFlags,
508    pub dst_access_mask: vk::AccessFlags,
509    pub dependency_flags: vk::DependencyFlags,
510}
511
512impl SubpassDependency {
513    pub fn new(src_subpass: u32, dst_subpass: u32) -> Self {
514        Self {
515            src_subpass,
516            dst_subpass,
517            src_stage_mask: vk::PipelineStageFlags::empty(),
518            dst_stage_mask: vk::PipelineStageFlags::empty(),
519            src_access_mask: vk::AccessFlags::empty(),
520            dst_access_mask: vk::AccessFlags::empty(),
521            dependency_flags: vk::DependencyFlags::empty(),
522        }
523    }
524}
525
526impl From<SubpassDependency> for vk::SubpassDependency2<'_> {
527    fn from(value: SubpassDependency) -> Self {
528        vk::SubpassDependency2::default()
529            .src_subpass(value.src_subpass)
530            .dst_subpass(value.dst_subpass)
531            .src_stage_mask(value.src_stage_mask)
532            .dst_stage_mask(value.dst_stage_mask)
533            .src_access_mask(value.src_access_mask)
534            .dst_access_mask(value.dst_access_mask)
535            .dependency_flags(value.dependency_flags)
536    }
537}
538
539#[derive(Clone, Debug, Eq, Hash, PartialEq)]
540pub(crate) struct SubpassInfo {
541    pub color_attachments: Vec<AttachmentRef>,
542    pub color_resolve_attachments: Vec<AttachmentRef>,
543    pub correlated_view_mask: u32,
544    pub depth_stencil_attachment: Option<AttachmentRef>,
545    pub depth_stencil_resolve_attachment:
546        Option<(AttachmentRef, Option<ResolveMode>, Option<ResolveMode>)>,
547    pub input_attachments: Vec<AttachmentRef>,
548    pub preserve_attachments: Vec<u32>,
549    pub view_mask: u32,
550}
551
552impl SubpassInfo {
553    pub fn with_capacity(capacity: usize) -> Self {
554        Self {
555            color_attachments: Vec::with_capacity(capacity),
556            color_resolve_attachments: Vec::with_capacity(capacity),
557            correlated_view_mask: 0,
558            depth_stencil_attachment: None,
559            depth_stencil_resolve_attachment: None,
560            input_attachments: Vec::with_capacity(capacity),
561            preserve_attachments: Vec::with_capacity(capacity),
562            view_mask: 0,
563        }
564    }
565}