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 = 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#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
479pub enum ResolveMode {
480 Average,
482
483 Maximum,
485
486 Minimum,
488
489 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}