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