1use {
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");
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#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
476pub enum ResolveMode {
477 Average,
479
480 Maximum,
482
483 Minimum,
485
486 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}