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