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 is_multiview = self
285 .info
286 .subpasses
287 .iter()
288 .any(|subpass| subpass.view_mask != 0);
289 let layers = if is_multiview {
290 1
291 } else {
292 key.attachments
293 .iter()
294 .map(|attachment| attachment.layer_count)
295 .max()
296 .unwrap_or(1)
297 };
298 let attachments = key
299 .attachments
300 .iter()
301 .map(|attachment| {
302 vk::FramebufferAttachmentImageInfo::default()
303 .flags(attachment.flags)
304 .width(attachment.width)
305 .height(attachment.height)
306 .layer_count(attachment.layer_count)
307 .usage(attachment.usage)
308 .view_formats(&attachment.view_formats)
309 })
310 .collect::<Box<_>>();
311 let mut imageless_info =
312 vk::FramebufferAttachmentsCreateInfoKHR::default().attachment_image_infos(&attachments);
313 let mut create_info = vk::FramebufferCreateInfo::default()
314 .flags(vk::FramebufferCreateFlags::IMAGELESS)
315 .render_pass(self.handle)
316 .width(attachments[0].width)
317 .height(attachments[0].height)
318 .layers(layers)
319 .push_next(&mut imageless_info);
320 create_info.attachment_count = self.info.attachments.len() as _;
321
322 let framebuffer =
323 unsafe { self.device.create_framebuffer(&create_info, None) }.map_err(|err| {
324 warn!("unable to create framebuffer: {err}");
325
326 DriverError::Unsupported
327 })?;
328
329 entry.insert(framebuffer);
330
331 Ok(framebuffer)
332 }
333
334 #[profiling::function]
335 pub(crate) fn pipeline_handle(
336 &mut self,
337 pipeline: &GraphicsPipeline,
338 depth_stencil: Option<DepthStencilInfo>,
339 subpass_idx: u32,
340 ) -> Result<vk::Pipeline, DriverError> {
341 let entry = self.graphic_pipelines.entry(GraphicPipelineKey {
342 depth_stencil,
343 layout: pipeline.inner.layout,
344 subpass_idx,
345 });
346 if let Entry::Occupied(entry) = entry {
347 let pipeline_handle = *entry.get();
348
349 if let Some(name) = Device::private_data_object_name(
350 &self.device,
351 vk::ObjectType::PIPELINE_LAYOUT,
352 pipeline.inner.layout,
353 ) && match Device::private_data_object_name(
354 &self.device,
355 vk::ObjectType::PIPELINE,
356 pipeline_handle,
357 ) {
358 None => true,
359 Some(previous) => previous != name,
360 } {
361 pipeline.set_variant_debug_name(pipeline_handle, self.handle, subpass_idx, &name);
362 }
363
364 return Ok(pipeline_handle);
365 }
366
367 let entry = match entry {
368 Entry::Vacant(entry) => entry,
369 _ => unreachable!(),
370 };
371
372 let color_blend_attachment_states = self.info.subpasses[subpass_idx as usize]
373 .color_attachments
374 .iter()
375 .map(|_| pipeline.inner.info.blend.into())
376 .collect::<Box<_>>();
377 let color_blend_state = vk::PipelineColorBlendStateCreateInfo::default()
378 .attachments(&color_blend_attachment_states);
379 let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
380 .dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]);
381 let multisample_state = vk::PipelineMultisampleStateCreateInfo::default()
382 .alpha_to_coverage_enable(pipeline.inner.multisample.alpha_to_coverage_enable)
383 .alpha_to_one_enable(pipeline.inner.multisample.alpha_to_one_enable)
384 .flags(pipeline.inner.multisample.flags)
385 .min_sample_shading(pipeline.inner.multisample.min_sample_shading)
386 .rasterization_samples(pipeline.inner.multisample.rasterization_samples.into())
387 .sample_shading_enable(pipeline.inner.multisample.sample_shading_enable)
388 .sample_mask(&pipeline.inner.multisample.sample_mask);
389 let specializations = pipeline
390 .inner
391 .shader_stages
392 .iter()
393 .map(|stage| stage.specialization.as_ref().map(Into::into))
394 .collect::<Box<_>>();
395 let stages = pipeline
396 .inner
397 .shader_stages
398 .iter()
399 .zip(specializations.iter())
400 .map(|(stage, specialization)| {
401 let mut info = vk::PipelineShaderStageCreateInfo::default()
402 .module(stage.module)
403 .name(&stage.name)
404 .stage(stage.flags);
405
406 if let Some(specialization) = specialization {
407 info = info.specialization_info(specialization);
408 }
409
410 info
411 })
412 .collect::<Box<_>>();
413 let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::default()
414 .vertex_attribute_descriptions(
415 &pipeline.inner.vertex_input.vertex_attribute_descriptions,
416 )
417 .vertex_binding_descriptions(&pipeline.inner.vertex_input.vertex_binding_descriptions);
418 let viewport_state = vk::PipelineViewportStateCreateInfo::default()
419 .viewport_count(1)
420 .scissor_count(1);
421 let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo {
422 topology: pipeline.inner.info.topology,
423 ..Default::default()
424 };
425 let depth_stencil = depth_stencil.map(Into::into).unwrap_or_default();
426 let rasterization_state = vk::PipelineRasterizationStateCreateInfo {
427 front_face: pipeline.inner.info.front_face,
428 line_width: 1.0,
429 polygon_mode: pipeline.inner.info.polygon_mode,
430 cull_mode: pipeline.inner.info.cull_mode,
431 ..Default::default()
432 };
433 let create_info = vk::GraphicsPipelineCreateInfo::default()
434 .color_blend_state(&color_blend_state)
435 .depth_stencil_state(&depth_stencil)
436 .dynamic_state(&dynamic_state)
437 .input_assembly_state(&input_assembly_state)
438 .layout(pipeline.inner.layout)
439 .multisample_state(&multisample_state)
440 .rasterization_state(&rasterization_state)
441 .render_pass(self.handle)
442 .stages(&stages)
443 .subpass(subpass_idx)
444 .vertex_input_state(&vertex_input_state)
445 .viewport_state(&viewport_state);
446
447 let pipeline_handle = unsafe {
448 self.device.create_graphics_pipelines(
449 Device::pipeline_cache(&self.device),
450 slice::from_ref(&create_info),
451 None,
452 )
453 }
454 .map_err(|(_, err)| {
455 warn!("create_graphics_pipelines: {err}\n{:#?}", create_info);
456
457 DriverError::Unsupported
458 })?
459 .into_iter()
460 .find(|handle| !handle.is_null())
461 .ok_or_else(|| {
462 warn!("missing pipeline handle");
463
464 DriverError::Unsupported
465 })?;
466
467 if let Some(name) = Device::private_data_object_name(
468 &self.device,
469 vk::ObjectType::PIPELINE_LAYOUT,
470 pipeline.inner.layout,
471 ) && match Device::private_data_object_name(
472 &self.device,
473 vk::ObjectType::PIPELINE,
474 pipeline_handle,
475 ) {
476 None => true,
477 Some(previous) => previous != name,
478 } {
479 pipeline.set_variant_debug_name(pipeline_handle, self.handle, subpass_idx, &name);
480 }
481
482 entry.insert(pipeline_handle);
483
484 Ok(pipeline_handle)
485 }
486}
487
488impl Drop for RenderPass {
489 #[profiling::function]
490 fn drop(&mut self) {
491 if panicking() {
492 return;
493 }
494
495 for (_, framebuffer) in self.framebuffers.drain() {
496 unsafe {
497 self.device.destroy_framebuffer(framebuffer, None);
498 }
499 }
500
501 for (_, pipeline) in self.graphic_pipelines.drain() {
502 Device::clear_private_data_object_name(
503 &self.device,
504 vk::ObjectType::PIPELINE,
505 pipeline,
506 )
507 .unwrap_or_else(|err| warn!("unable to clear private data object name: {err}"));
508
509 unsafe {
510 self.device.destroy_pipeline(pipeline, None);
511 }
512 }
513
514 unsafe {
515 self.device.destroy_render_pass(self.handle, None);
516 }
517 }
518}
519
520#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
524pub(crate) struct RenderPassInfo {
525 pub(crate) attachments: Vec<AttachmentInfo>,
526 pub(crate) subpasses: Vec<SubpassInfo>,
527 pub(crate) dependencies: Vec<SubpassDependency>,
528}
529
530#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
534pub enum ResolveMode {
535 Average,
537
538 Maximum,
540
541 Minimum,
543
544 SampleZero,
546}
547
548impl From<ResolveMode> for vk::ResolveModeFlags {
549 fn from(mode: ResolveMode) -> Self {
550 match mode {
551 ResolveMode::Average => vk::ResolveModeFlags::AVERAGE,
552 ResolveMode::Maximum => vk::ResolveModeFlags::MAX,
553 ResolveMode::Minimum => vk::ResolveModeFlags::MIN,
554 ResolveMode::SampleZero => vk::ResolveModeFlags::SAMPLE_ZERO,
555 }
556 }
557}
558
559#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
560pub(crate) struct SubpassDependency {
561 pub src_subpass: u32,
562 pub dst_subpass: u32,
563 pub src_stage_mask: vk::PipelineStageFlags,
564 pub dst_stage_mask: vk::PipelineStageFlags,
565 pub src_access_mask: vk::AccessFlags,
566 pub dst_access_mask: vk::AccessFlags,
567 pub dependency_flags: vk::DependencyFlags,
568}
569
570impl SubpassDependency {
571 pub fn new(src_subpass: u32, dst_subpass: u32) -> Self {
572 Self {
573 src_subpass,
574 dst_subpass,
575 src_stage_mask: vk::PipelineStageFlags::empty(),
576 dst_stage_mask: vk::PipelineStageFlags::empty(),
577 src_access_mask: vk::AccessFlags::empty(),
578 dst_access_mask: vk::AccessFlags::empty(),
579 dependency_flags: vk::DependencyFlags::empty(),
580 }
581 }
582}
583
584impl From<SubpassDependency> for vk::SubpassDependency2<'_> {
585 fn from(value: SubpassDependency) -> Self {
586 vk::SubpassDependency2::default()
587 .src_subpass(value.src_subpass)
588 .dst_subpass(value.dst_subpass)
589 .src_stage_mask(value.src_stage_mask)
590 .dst_stage_mask(value.dst_stage_mask)
591 .src_access_mask(value.src_access_mask)
592 .dst_access_mask(value.dst_access_mask)
593 .dependency_flags(value.dependency_flags)
594 }
595}
596
597#[derive(Clone, Debug, Eq, Hash, PartialEq)]
598pub(crate) struct SubpassInfo {
599 pub color_attachments: Vec<AttachmentRef>,
600 pub color_resolve_attachments: Vec<AttachmentRef>,
601 pub correlated_view_mask: u32,
602 pub depth_stencil_attachment: Option<AttachmentRef>,
603 pub depth_stencil_resolve_attachment:
604 Option<(AttachmentRef, Option<ResolveMode>, Option<ResolveMode>)>,
605 pub input_attachments: Vec<AttachmentRef>,
606 pub preserve_attachments: Vec<u32>,
607 pub view_mask: u32,
608}
609
610impl SubpassInfo {
611 pub fn with_capacity(capacity: usize) -> Self {
612 Self {
613 color_attachments: Vec::with_capacity(capacity),
614 color_resolve_attachments: Vec::with_capacity(capacity),
615 correlated_view_mask: 0,
616 depth_stencil_attachment: None,
617 depth_stencil_resolve_attachment: None,
618 input_attachments: Vec::with_capacity(capacity),
619 preserve_attachments: Vec::with_capacity(capacity),
620 view_mask: 0,
621 }
622 }
623}