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