1use {
4 super::{
5 DriverError,
6 device::Device,
7 image::SampleCount,
8 merge_push_constant_ranges,
9 shader::{DescriptorBindingMap, PipelineDescriptorInfo, Shader, SpecializationMap},
10 },
11 crate::{driver::DescriptorSetLayout, lazy_str},
12 ash::vk,
13 derive_builder::Builder,
14 log::{Level::Trace, log_enabled, trace, warn},
15 ordered_float::OrderedFloat,
16 std::{
17 collections::HashSet,
18 ffi::CString,
19 fmt::{Debug, Formatter},
20 hash::{Hash, Hasher},
21 sync::Arc,
22 thread::panicking,
23 },
24};
25
26const RGBA_COLOR_COMPONENTS: vk::ColorComponentFlags = vk::ColorComponentFlags::from_raw(
27 vk::ColorComponentFlags::R.as_raw()
28 | vk::ColorComponentFlags::G.as_raw()
29 | vk::ColorComponentFlags::B.as_raw()
30 | vk::ColorComponentFlags::A.as_raw(),
31);
32
33#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
38#[builder(
39 build_fn(private, name = "fallible_build"),
40 derive(Clone, Copy, Debug),
41 pattern = "owned"
42)]
43pub struct BlendInfo {
44 #[builder(default = "false")]
49 pub blend_enable: bool,
50
51 #[builder(default = "vk::BlendFactor::SRC_COLOR")]
53 pub src_color_blend_factor: vk::BlendFactor,
54
55 #[builder(default = "vk::BlendFactor::ONE_MINUS_DST_COLOR")]
57 pub dst_color_blend_factor: vk::BlendFactor,
58
59 #[builder(default = "vk::BlendOp::ADD")]
62 pub color_blend_op: vk::BlendOp,
63
64 #[builder(default = "vk::BlendFactor::ZERO")]
66 pub src_alpha_blend_factor: vk::BlendFactor,
67
68 #[builder(default = "vk::BlendFactor::ZERO")]
70 pub dst_alpha_blend_factor: vk::BlendFactor,
71
72 #[builder(default = "vk::BlendOp::ADD")]
75 pub alpha_blend_op: vk::BlendOp,
76
77 #[builder(default = "RGBA_COLOR_COMPONENTS")]
80 pub color_write_mask: vk::ColorComponentFlags,
81}
82
83impl BlendInfo {
84 pub const ADDITIVE: Self = Self {
86 blend_enable: true,
87 src_color_blend_factor: vk::BlendFactor::ONE,
88 dst_color_blend_factor: vk::BlendFactor::ONE,
89 color_blend_op: vk::BlendOp::ADD,
90 src_alpha_blend_factor: vk::BlendFactor::ONE,
91 dst_alpha_blend_factor: vk::BlendFactor::ONE,
92 alpha_blend_op: vk::BlendOp::ADD,
93 color_write_mask: RGBA_COLOR_COMPONENTS,
94 };
95
96 pub const REPLACE: Self = Self {
98 blend_enable: false,
99 src_color_blend_factor: vk::BlendFactor::SRC_COLOR,
100 dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_DST_COLOR,
101 color_blend_op: vk::BlendOp::ADD,
102 src_alpha_blend_factor: vk::BlendFactor::ZERO,
103 dst_alpha_blend_factor: vk::BlendFactor::ZERO,
104 alpha_blend_op: vk::BlendOp::ADD,
105 color_write_mask: RGBA_COLOR_COMPONENTS,
106 };
107
108 pub const ALPHA: Self = Self {
110 blend_enable: true,
111 src_color_blend_factor: vk::BlendFactor::SRC_ALPHA,
112 dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
113 color_blend_op: vk::BlendOp::ADD,
114 src_alpha_blend_factor: vk::BlendFactor::SRC_ALPHA,
115 dst_alpha_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
116 alpha_blend_op: vk::BlendOp::ADD,
117 color_write_mask: RGBA_COLOR_COMPONENTS,
118 };
119
120 pub const COLOR_WRITE_DISABLED: Self = Self {
125 blend_enable: false,
126 src_color_blend_factor: vk::BlendFactor::SRC_COLOR,
127 dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_DST_COLOR,
128 color_blend_op: vk::BlendOp::ADD,
129 src_alpha_blend_factor: vk::BlendFactor::ZERO,
130 dst_alpha_blend_factor: vk::BlendFactor::ZERO,
131 alpha_blend_op: vk::BlendOp::ADD,
132 color_write_mask: vk::ColorComponentFlags::empty(),
133 };
134
135 pub const PRE_MULTIPLIED_ALPHA: Self = Self {
138 blend_enable: true,
139 src_color_blend_factor: vk::BlendFactor::SRC_ALPHA,
140 dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
141 color_blend_op: vk::BlendOp::ADD,
142 src_alpha_blend_factor: vk::BlendFactor::ONE,
143 dst_alpha_blend_factor: vk::BlendFactor::ONE,
144 alpha_blend_op: vk::BlendOp::ADD,
145 color_write_mask: RGBA_COLOR_COMPONENTS,
146 };
147
148 pub fn builder() -> BlendInfoBuilder {
150 BlendInfoBuilder::default()
151 }
152
153 pub fn into_builder(self) -> BlendInfoBuilder {
155 BlendInfoBuilder {
156 blend_enable: Some(self.blend_enable),
157 src_color_blend_factor: Some(self.src_color_blend_factor),
158 dst_color_blend_factor: Some(self.dst_color_blend_factor),
159 color_blend_op: Some(self.color_blend_op),
160 src_alpha_blend_factor: Some(self.src_alpha_blend_factor),
161 dst_alpha_blend_factor: Some(self.dst_alpha_blend_factor),
162 alpha_blend_op: Some(self.alpha_blend_op),
163 color_write_mask: Some(self.color_write_mask),
164 }
165 }
166}
167
168impl Default for BlendInfo {
170 fn default() -> Self {
171 Self::REPLACE
172 }
173}
174
175impl From<BlendInfo> for vk::PipelineColorBlendAttachmentState {
176 fn from(mode: BlendInfo) -> Self {
177 Self {
178 blend_enable: mode.blend_enable as _,
179 src_color_blend_factor: mode.src_color_blend_factor,
180 dst_color_blend_factor: mode.dst_color_blend_factor,
181 color_blend_op: mode.color_blend_op,
182 src_alpha_blend_factor: mode.src_alpha_blend_factor,
183 dst_alpha_blend_factor: mode.dst_alpha_blend_factor,
184 alpha_blend_op: mode.alpha_blend_op,
185 color_write_mask: mode.color_write_mask,
186 }
187 }
188}
189
190impl BlendInfoBuilder {
191 pub fn build(self) -> BlendInfo {
193 self.fallible_build().expect("invalid blend info")
194 }
195}
196
197#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
201#[builder(
202 build_fn(private, name = "fallible_build"),
203 derive(Clone, Copy, Debug),
204 pattern = "owned"
205)]
206pub struct DepthStencilInfo {
207 #[builder(default)]
211 pub back: StencilMode,
212
213 #[builder(default)]
218 pub bounds_test: bool,
219
220 #[builder(default)]
227 pub compare_op: vk::CompareOp,
228
229 #[builder(default)]
234 pub depth_test: bool,
235
236 #[builder(default)]
243 pub depth_write: bool,
244
245 #[builder(default)]
249 pub front: StencilMode,
250
251 #[builder(default, setter(into))]
257 pub min: OrderedFloat<f32>,
258
259 #[builder(default, setter(into))]
265 pub max: OrderedFloat<f32>,
266
267 #[builder(default)]
272 pub stencil_test: bool,
273}
274
275impl DepthStencilInfo {
276 pub const IGNORE: Self = Self {
280 back: StencilMode::IGNORE,
281 bounds_test: false,
282 compare_op: vk::CompareOp::NEVER,
283 depth_test: false,
284 depth_write: false,
285 front: StencilMode::IGNORE,
286 min: OrderedFloat(0.0),
287 max: OrderedFloat(0.0),
288 stencil_test: false,
289 };
290
291 pub const fn depth_read(compare_op: vk::CompareOp) -> Self {
293 Self {
294 depth_test: true,
295 compare_op,
296 min: OrderedFloat(0.0),
297 max: OrderedFloat(1.0),
298 ..Self::IGNORE
299 }
300 }
301
302 pub const fn depth_write(compare_op: vk::CompareOp) -> Self {
304 Self {
305 depth_test: true,
306 depth_write: true,
307 compare_op,
308 min: OrderedFloat(0.0),
309 max: OrderedFloat(1.0),
310 ..Self::IGNORE
311 }
312 }
313
314 pub const fn depth_read_write(compare_op: vk::CompareOp) -> Self {
316 Self::depth_write(compare_op)
317 }
318
319 pub const DEPTH_WRITE_LESS: Self = Self::depth_write(vk::CompareOp::LESS);
321
322 pub const DEPTH_WRITE_LESS_OR_EQUAL: Self = Self::depth_write(vk::CompareOp::LESS_OR_EQUAL);
324
325 pub const DEPTH_WRITE_GREATER: Self = Self::depth_write(vk::CompareOp::GREATER);
327
328 pub const DEPTH_WRITE_GREATER_OR_EQUAL: Self =
330 Self::depth_write(vk::CompareOp::GREATER_OR_EQUAL);
331
332 pub const DEPTH_WRITE_LESS_IGNORE_STENCIL: Self = Self::DEPTH_WRITE_LESS;
334
335 pub fn builder() -> DepthStencilInfoBuilder {
337 Default::default()
338 }
339
340 pub fn into_builder(self) -> DepthStencilInfoBuilder {
342 DepthStencilInfoBuilder {
343 back: Some(self.back),
344 bounds_test: Some(self.bounds_test),
345 compare_op: Some(self.compare_op),
346 depth_test: Some(self.depth_test),
347 depth_write: Some(self.depth_write),
348 front: Some(self.front),
349 max: Some(self.max),
350 min: Some(self.min),
351 stencil_test: Some(self.stencil_test),
352 }
353 }
354}
355
356impl Default for DepthStencilInfo {
357 fn default() -> Self {
358 Self::IGNORE
359 }
360}
361
362impl From<DepthStencilInfo> for vk::PipelineDepthStencilStateCreateInfo<'_> {
363 fn from(info: DepthStencilInfo) -> Self {
364 Self::default()
365 .back(info.back.into())
366 .depth_bounds_test_enable(info.bounds_test as _)
367 .depth_compare_op(info.compare_op)
368 .depth_test_enable(info.depth_test as _)
369 .depth_write_enable(info.depth_write as _)
370 .front(info.front.into())
371 .max_depth_bounds(info.max.into_inner())
372 .min_depth_bounds(info.min.into_inner())
373 .stencil_test_enable(info.stencil_test as _)
374 }
375}
376
377impl DepthStencilInfoBuilder {
378 pub fn build(self) -> DepthStencilInfo {
380 self.fallible_build().expect("invalid depth stencil info")
381 }
382}
383
384#[derive(Clone)]
390#[read_only::cast]
391pub struct GraphicsPipeline {
392 pub(crate) inner: Arc<GraphicsPipelineInner>,
393}
394
395impl GraphicsPipeline {
396 #[profiling::function]
432 pub fn create<S>(
433 device: &Device,
434 info: impl Into<GraphicsPipelineInfo>,
435 shaders: impl IntoIterator<Item = S>,
436 ) -> Result<Self, DriverError>
437 where
438 S: TryInto<Shader>,
439 S::Error: Into<DriverError>,
440 {
441 trace!("create");
442
443 let device = device.clone();
444 let info = info.into();
445 let shaders = shaders
446 .into_iter()
447 .map(|shader| shader.try_into().map_err(Into::into))
448 .collect::<Result<Vec<_>, _>>()?;
449
450 let vertex_input = shaders
451 .iter()
452 .find(|shader| shader.stage == vk::ShaderStageFlags::VERTEX)
453 .ok_or(DriverError::InvalidData)?
454 .try_vertex_input()?;
455
456 let has_fragment_stage = shaders
458 .iter()
459 .any(|shader| shader.stage.contains(vk::ShaderStageFlags::FRAGMENT));
460 let has_tessellation_stage = shaders.iter().any(|shader| {
461 shader
462 .stage
463 .contains(vk::ShaderStageFlags::TESSELLATION_CONTROL)
464 }) && shaders.iter().any(|shader| {
465 shader
466 .stage
467 .contains(vk::ShaderStageFlags::TESSELLATION_EVALUATION)
468 });
469 let has_geometry_stage = shaders
470 .iter()
471 .any(|shader| shader.stage.contains(vk::ShaderStageFlags::GEOMETRY));
472
473 debug_assert!(
474 has_fragment_stage || has_tessellation_stage || has_geometry_stage,
475 "invalid shader stage combination"
476 );
477
478 let mut descriptor_bindings = Shader::merge_descriptor_bindings(
479 shaders.iter().map(|shader| shader.descriptor_bindings()),
480 )?;
481 let mut bindless_descriptors = HashSet::new();
482 for (descriptor, (descriptor_info, _)) in descriptor_bindings.iter_mut() {
483 if descriptor_info.binding_count() == 0 {
484 bindless_descriptors.insert(*descriptor);
485 descriptor_info.set_binding_count(info.bindless_descriptor_count);
486 }
487 }
488
489 let descriptor_info =
490 PipelineDescriptorInfo::create(&device, &descriptor_bindings, &bindless_descriptors)?;
491 let descriptor_sets_layouts = descriptor_info
492 .layouts
493 .values()
494 .map(DescriptorSetLayout::handle)
495 .collect::<Box<_>>();
496
497 let push_constants = shaders
498 .iter()
499 .map(|shader| shader.push_constant_range())
500 .filter_map(|mut push_const| push_const.take())
501 .collect::<Vec<_>>();
502
503 let input_attachments = shaders
504 .iter()
505 .find(|shader| shader.stage == vk::ShaderStageFlags::FRAGMENT)
506 .map(|shader| {
507 let (input, write) = shader.attachments();
508 let (input, write) = (
509 input
510 .collect::<HashSet<_>>()
511 .into_iter()
512 .collect::<Box<_>>(),
513 write.collect::<HashSet<_>>(),
514 );
515
516 if log_enabled!(Trace) {
517 for input in input.iter() {
518 trace!("detected input attachment {input}");
519 }
520
521 for write in &write {
522 trace!("detected write attachment {write}");
523 }
524 }
525
526 input
527 })
528 .unwrap_or_default();
529
530 unsafe {
531 let layout = device
532 .create_pipeline_layout(
533 &vk::PipelineLayoutCreateInfo::default()
534 .set_layouts(&descriptor_sets_layouts)
535 .push_constant_ranges(&push_constants),
536 None,
537 )
538 .map_err(|err| {
539 warn!("unable to create graphics pipeline layout: {err}");
540
541 DriverError::Unsupported
542 })?;
543 let shader_stages = shaders
544 .into_iter()
545 .map(|shader| {
546 let shader_module = device
547 .create_shader_module(
548 &vk::ShaderModuleCreateInfo::default().code(shader.spirv.words()),
549 None,
550 )
551 .map_err(|err| {
552 warn!("unable to create graphic shader module: {err}");
553
554 DriverError::Unsupported
555 })?;
556 let shader_stage = ShaderStage {
557 flags: shader.stage,
558 module: shader_module,
559 name: CString::new(shader.entry_name.as_str()).map_err(|err| {
560 warn!("invalid graphics shader entry name: {err}");
561
562 DriverError::InvalidData
563 })?,
564 specialization: shader.specialization,
565 };
566
567 Result::<_, DriverError>::Ok(shader_stage)
568 })
569 .collect::<Result<Box<_>, _>>()?;
570
571 let mut multisample = MultisampleState {
572 alpha_to_coverage_enable: info.alpha_to_coverage,
573 alpha_to_one_enable: info.alpha_to_one,
574 rasterization_samples: info.samples,
575 ..Default::default()
576 };
577
578 if let Some(OrderedFloat(min_sample_shading)) = info.min_sample_shading {
579 #[cfg(debug_assertions)]
580 if info.samples.is_single() {
581 warn!("unsupported sample rate shading of single-sample pipeline");
587 }
588
589 debug_assert!(
591 device.physical.features_v1_0.sample_rate_shading,
592 "unsupported sample rate shading feature"
593 );
594
595 multisample.sample_shading_enable = true;
596 multisample.min_sample_shading = min_sample_shading;
597 }
598
599 let push_constants = merge_push_constant_ranges(&push_constants).into_boxed_slice();
600
601 Ok(Self {
602 inner: Arc::new(GraphicsPipelineInner {
603 descriptor_bindings,
604 descriptor_info,
605 device,
606 info,
607 input_attachments,
608 layout,
609 multisample,
610 push_constants,
611 shader_stages,
612 vertex_input,
613 }),
614 })
615 }
616 }
617
618 pub fn device(&self) -> &Device {
620 &self.inner.device
621 }
622
623 pub fn info(&self) -> GraphicsPipelineInfo {
625 self.inner.info
626 }
627
628 pub fn set_debug_name(&self, name: impl AsRef<str>) {
633 Device::try_set_debug_utils_object_name(
634 &self.inner.device,
635 self.inner.layout,
636 lazy_str!("{} (layout)", name.as_ref()),
637 );
638 Device::try_set_private_data_object_name(
639 &self.inner.device,
640 vk::ObjectType::PIPELINE_LAYOUT,
641 self.inner.layout,
642 lazy_str!("{}", name.as_ref()),
643 );
644
645 for (set_idx, layout) in &self.inner.descriptor_info.layouts {
646 layout.set_debug_name(lazy_str!("{} (DS{set_idx})", name.as_ref()));
647 }
648 }
649
650 pub(crate) fn set_variant_debug_name(
651 &self,
652 pipeline_handle: vk::Pipeline,
653 render_pass: vk::RenderPass,
654 subpass_idx: u32,
655 name: impl AsRef<str>,
656 ) {
657 Device::try_set_debug_utils_object_name(
658 &self.inner.device,
659 pipeline_handle,
660 lazy_str!(
661 "{} (render pass {:?}, subpass {subpass_idx})",
662 name.as_ref(),
663 render_pass
664 ),
665 );
666 Device::try_set_private_data_object_name(
667 &self.inner.device,
668 vk::ObjectType::PIPELINE,
669 pipeline_handle,
670 name,
671 );
672 }
673
674 pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
676 self.set_debug_name(name);
677
678 self
679 }
680}
681
682impl Debug for GraphicsPipeline {
683 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
684 let mut res = f.debug_struct(stringify!(GraphicsPipeline));
685 let shader_stages = self
686 .inner
687 .shader_stages
688 .iter()
689 .map(|stage| stage.flags)
690 .collect::<Box<_>>();
691
692 if let Some(debug_name) = &Device::private_data_object_name(
693 &self.inner.device,
694 vk::ObjectType::PIPELINE_LAYOUT,
695 self.inner.layout,
696 ) {
697 res.field("debug_name", debug_name);
698 }
699
700 res.field("layout", &self.inner.layout)
701 .field("shader_stages", &shader_stages)
702 .field("input_attachments", &self.inner.input_attachments)
703 .finish_non_exhaustive()
704 }
705}
706
707impl Eq for GraphicsPipeline {}
708
709impl Hash for GraphicsPipeline {
710 fn hash<H: Hasher>(&self, state: &mut H) {
711 Arc::as_ptr(&self.inner).hash(state);
712 }
713}
714
715impl PartialEq for GraphicsPipeline {
716 fn eq(&self, other: &Self) -> bool {
717 Arc::ptr_eq(&self.inner, &other.inner)
718 }
719}
720
721#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
725#[builder(
726 build_fn(private, name = "fallible_build"),
727 derive(Clone, Copy, Debug),
728 pattern = "owned"
729)]
730pub struct GraphicsPipelineInfo {
731 #[builder(default)]
734 pub alpha_to_coverage: bool,
735
736 #[builder(default)]
739 pub alpha_to_one: bool,
740
741 #[builder(default = "8192")]
764 pub bindless_descriptor_count: u32,
765
766 #[builder(default)]
771 pub blend: BlendInfo,
772
773 #[builder(default = "vk::CullModeFlags::BACK")]
777 pub cull_mode: vk::CullModeFlags,
778
779 #[builder(default = "vk::FrontFace::COUNTER_CLOCKWISE")]
783 pub front_face: vk::FrontFace,
784
785 #[builder(default, setter(into, strip_option))]
787 pub min_sample_shading: Option<OrderedFloat<f32>>,
788
789 #[builder(default = "vk::PolygonMode::FILL")]
793 pub polygon_mode: vk::PolygonMode,
794
795 #[builder(default = "vk::PrimitiveTopology::TRIANGLE_LIST")]
799 pub topology: vk::PrimitiveTopology,
800
801 #[builder(default = "SampleCount::Type1")]
807 pub samples: SampleCount,
808}
809
810impl GraphicsPipelineInfo {
811 pub fn builder() -> GraphicsPipelineInfoBuilder {
813 Default::default()
814 }
815
816 pub fn into_builder(self) -> GraphicsPipelineInfoBuilder {
818 GraphicsPipelineInfoBuilder {
819 alpha_to_coverage: Some(self.alpha_to_coverage),
820 alpha_to_one: Some(self.alpha_to_one),
821 bindless_descriptor_count: Some(self.bindless_descriptor_count),
822 blend: Some(self.blend),
823 cull_mode: Some(self.cull_mode),
824 front_face: Some(self.front_face),
825 min_sample_shading: Some(self.min_sample_shading),
826 polygon_mode: Some(self.polygon_mode),
827 topology: Some(self.topology),
828 samples: Some(self.samples),
829 }
830 }
831}
832
833impl Default for GraphicsPipelineInfo {
834 fn default() -> Self {
835 Self {
836 alpha_to_coverage: false,
837 alpha_to_one: false,
838 bindless_descriptor_count: 8192,
839 blend: BlendInfo::REPLACE,
840 cull_mode: vk::CullModeFlags::BACK,
841 front_face: vk::FrontFace::COUNTER_CLOCKWISE,
842 min_sample_shading: None,
843 polygon_mode: vk::PolygonMode::FILL,
844 topology: vk::PrimitiveTopology::TRIANGLE_LIST,
845 samples: SampleCount::Type1,
846 }
847 }
848}
849
850impl From<GraphicsPipelineInfoBuilder> for GraphicsPipelineInfo {
851 fn from(info: GraphicsPipelineInfoBuilder) -> Self {
852 info.build()
853 }
854}
855
856impl GraphicsPipelineInfoBuilder {
857 #[inline(always)]
859 pub fn build(self) -> GraphicsPipelineInfo {
860 self.fallible_build()
861 .expect("invalid graphics pipeline info")
862 }
863}
864
865#[derive(Debug)]
866pub(crate) struct GraphicsPipelineInner {
867 pub descriptor_bindings: DescriptorBindingMap,
868 pub descriptor_info: PipelineDescriptorInfo,
869 pub device: Device,
870 pub info: GraphicsPipelineInfo,
871 pub input_attachments: Box<[u32]>,
872 pub layout: vk::PipelineLayout,
873 pub multisample: MultisampleState,
874 pub push_constants: Box<[vk::PushConstantRange]>,
875 pub shader_stages: Box<[ShaderStage]>,
876 pub vertex_input: VertexInputState,
877}
878
879impl Drop for GraphicsPipelineInner {
880 #[profiling::function]
881 fn drop(&mut self) {
882 if panicking() {
883 return;
884 }
885
886 Device::try_clear_private_data_object_name(
887 &self.device,
888 vk::ObjectType::PIPELINE_LAYOUT,
889 self.layout,
890 );
891
892 unsafe {
893 self.device.destroy_pipeline_layout(self.layout, None);
894 }
895
896 for shader_stage in &mut self.shader_stages {
897 unsafe {
898 self.device.destroy_shader_module(shader_stage.module, None);
899 }
900 }
901 }
902}
903
904#[derive(Debug, Default)]
905pub(crate) struct MultisampleState {
906 pub alpha_to_coverage_enable: bool,
907 pub alpha_to_one_enable: bool,
908 pub flags: vk::PipelineMultisampleStateCreateFlags,
909 pub min_sample_shading: f32,
910 pub rasterization_samples: SampleCount,
911 pub sample_mask: Vec<u32>,
912 pub sample_shading_enable: bool,
913}
914
915#[derive(Debug)]
916pub(crate) struct ShaderStage {
917 pub flags: vk::ShaderStageFlags,
918 pub module: vk::ShaderModule,
919 pub name: CString, pub specialization: Option<SpecializationMap>,
921}
922
923#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
927pub struct StencilMode {
928 pub fail_op: vk::StencilOp,
930
931 pub pass_op: vk::StencilOp,
933
934 pub depth_fail_op: vk::StencilOp,
936
937 pub compare_op: vk::CompareOp,
939
940 pub compare_mask: u32,
942
943 pub write_mask: u32,
946
947 pub reference: u32,
950}
951
952impl StencilMode {
953 pub const IGNORE: Self = Self {
955 fail_op: vk::StencilOp::KEEP,
956 pass_op: vk::StencilOp::KEEP,
957 depth_fail_op: vk::StencilOp::KEEP,
958 compare_op: vk::CompareOp::NEVER,
959 compare_mask: 0,
960 write_mask: 0,
961 reference: 0,
962 };
963}
964
965impl Default for StencilMode {
966 fn default() -> Self {
967 Self::IGNORE
968 }
969}
970
971impl From<StencilMode> for vk::StencilOpState {
972 fn from(mode: StencilMode) -> Self {
973 Self {
974 fail_op: mode.fail_op,
975 pass_op: mode.pass_op,
976 depth_fail_op: mode.depth_fail_op,
977 compare_op: mode.compare_op,
978 compare_mask: mode.compare_mask,
979 write_mask: mode.write_mask,
980 reference: mode.reference,
981 }
982 }
983}
984
985#[derive(Clone, Debug, Default)]
986pub(crate) struct VertexInputState {
987 pub vertex_binding_descriptions: Vec<vk::VertexInputBindingDescription>,
988 pub vertex_attribute_descriptions: Vec<vk::VertexInputAttributeDescription>,
989}
990
991#[cfg(test)]
992mod test {
993 use super::*;
994
995 #[test]
996 pub fn blend_info() {
997 let info = BlendInfo::default();
998 let builder = info.into_builder().build();
999
1000 assert_eq!(info, builder);
1001 }
1002
1003 #[test]
1004 pub fn blend_info_builder() {
1005 let info = BlendInfo::default();
1006 let builder = BlendInfoBuilder::default().build();
1007
1008 assert_eq!(info, builder);
1009 }
1010
1011 #[test]
1012 pub fn depth_stencil_info() {
1013 let info = DepthStencilInfo::default();
1014 let builder = info.into_builder().build();
1015
1016 assert_eq!(info, builder);
1017 }
1018
1019 #[test]
1020 pub fn depth_stencil_info_builder() {
1021 let info = DepthStencilInfo::default();
1022 let builder = DepthStencilInfoBuilder::default().build();
1023
1024 assert_eq!(info, builder);
1025 }
1026
1027 #[test]
1028 pub fn graphics_pipeline_info() {
1029 let info = GraphicsPipelineInfo::default();
1030 let builder = info.into_builder().build();
1031
1032 assert_eq!(info, builder);
1033 }
1034
1035 #[test]
1036 pub fn graphics_pipeline_info_builder() {
1037 let info = GraphicsPipelineInfo::default();
1038 let builder = GraphicsPipelineInfoBuilder::default().build();
1039
1040 assert_eq!(info, builder);
1041 }
1042}