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::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 for (descriptor_info, _) in descriptor_bindings.values_mut() {
482 if descriptor_info.binding_count() == 0 {
483 descriptor_info.set_binding_count(info.bindless_descriptor_count);
484 }
485 }
486
487 let descriptor_info = PipelineDescriptorInfo::create(&device, &descriptor_bindings)?;
488 let descriptor_sets_layouts = descriptor_info
489 .layouts
490 .values()
491 .map(|descriptor_set_layout| descriptor_set_layout.handle)
492 .collect::<Box<_>>();
493
494 let push_constants = shaders
495 .iter()
496 .map(|shader| shader.push_constant_range())
497 .filter_map(|mut push_const| push_const.take())
498 .collect::<Vec<_>>();
499
500 let input_attachments = shaders
501 .iter()
502 .find(|shader| shader.stage == vk::ShaderStageFlags::FRAGMENT)
503 .map(|shader| {
504 let (input, write) = shader.attachments();
505 let (input, write) = (
506 input
507 .collect::<HashSet<_>>()
508 .into_iter()
509 .collect::<Box<_>>(),
510 write.collect::<HashSet<_>>(),
511 );
512
513 if log_enabled!(Trace) {
514 for input in input.iter() {
515 trace!("detected input attachment {input}");
516 }
517
518 for write in &write {
519 trace!("detected write attachment {write}");
520 }
521 }
522
523 input
524 })
525 .unwrap_or_default();
526
527 unsafe {
528 let layout = device
529 .create_pipeline_layout(
530 &vk::PipelineLayoutCreateInfo::default()
531 .set_layouts(&descriptor_sets_layouts)
532 .push_constant_ranges(&push_constants),
533 None,
534 )
535 .map_err(|err| {
536 warn!("unable to create graphics pipeline layout: {err}");
537
538 DriverError::Unsupported
539 })?;
540 let shader_stages = shaders
541 .into_iter()
542 .map(|shader| {
543 let shader_module = device
544 .create_shader_module(
545 &vk::ShaderModuleCreateInfo::default().code(shader.spirv.words()),
546 None,
547 )
548 .map_err(|err| {
549 warn!("unable to create graphic shader module: {err}");
550
551 DriverError::Unsupported
552 })?;
553 let shader_stage = ShaderStage {
554 flags: shader.stage,
555 module: shader_module,
556 name: CString::new(shader.entry_name.as_str()).map_err(|err| {
557 warn!("invalid graphics shader entry name: {err}");
558
559 DriverError::InvalidData
560 })?,
561 specialization: shader.specialization,
562 };
563
564 Result::<_, DriverError>::Ok(shader_stage)
565 })
566 .collect::<Result<Box<_>, _>>()?;
567
568 let mut multisample = MultisampleState {
569 alpha_to_coverage_enable: info.alpha_to_coverage,
570 alpha_to_one_enable: info.alpha_to_one,
571 rasterization_samples: info.samples,
572 ..Default::default()
573 };
574
575 if let Some(OrderedFloat(min_sample_shading)) = info.min_sample_shading {
576 #[cfg(debug_assertions)]
577 if info.samples.is_single() {
578 warn!("unsupported sample rate shading of single-sample pipeline");
584 }
585
586 debug_assert!(
588 device.physical.features_v1_0.sample_rate_shading,
589 "unsupported sample rate shading feature"
590 );
591
592 multisample.sample_shading_enable = true;
593 multisample.min_sample_shading = min_sample_shading;
594 }
595
596 let push_constants = merge_push_constant_ranges(&push_constants).into_boxed_slice();
597
598 Ok(Self {
599 inner: Arc::new(GraphicsPipelineInner {
600 descriptor_bindings,
601 descriptor_info,
602 device,
603 info,
604 input_attachments,
605 layout,
606 multisample,
607 push_constants,
608 shader_stages,
609 vertex_input,
610 }),
611 })
612 }
613 }
614
615 pub fn device(&self) -> &Device {
617 &self.inner.device
618 }
619
620 pub fn info(&self) -> GraphicsPipelineInfo {
622 self.inner.info
623 }
624
625 pub fn set_debug_name(&self, name: impl AsRef<str>) {
630 Device::try_set_debug_utils_object_name(
631 &self.inner.device,
632 self.inner.layout,
633 lazy_str!("{} (layout)", name.as_ref()),
634 );
635 Device::try_set_private_data_object_name(
636 &self.inner.device,
637 vk::ObjectType::PIPELINE_LAYOUT,
638 self.inner.layout,
639 lazy_str!("{}", name.as_ref()),
640 );
641
642 for (set_idx, layout) in &self.inner.descriptor_info.layouts {
643 layout.set_debug_name(lazy_str!("{} (DS{set_idx})", name.as_ref()));
644 }
645 }
646
647 pub(crate) fn set_variant_debug_name(
648 &self,
649 pipeline_handle: vk::Pipeline,
650 render_pass: vk::RenderPass,
651 subpass_idx: u32,
652 name: impl AsRef<str>,
653 ) {
654 Device::try_set_debug_utils_object_name(
655 &self.inner.device,
656 pipeline_handle,
657 lazy_str!(
658 "{} (render pass {:?}, subpass {subpass_idx})",
659 name.as_ref(),
660 render_pass
661 ),
662 );
663 Device::try_set_private_data_object_name(
664 &self.inner.device,
665 vk::ObjectType::PIPELINE,
666 pipeline_handle,
667 name,
668 );
669 }
670
671 pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
673 self.set_debug_name(name);
674
675 self
676 }
677}
678
679impl Debug for GraphicsPipeline {
680 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
681 let mut res = f.debug_struct(stringify!(GraphicsPipeline));
682 let shader_stages = self
683 .inner
684 .shader_stages
685 .iter()
686 .map(|stage| stage.flags)
687 .collect::<Box<_>>();
688
689 if let Some(debug_name) = &Device::private_data_object_name(
690 &self.inner.device,
691 vk::ObjectType::PIPELINE_LAYOUT,
692 self.inner.layout,
693 ) {
694 res.field("debug_name", debug_name);
695 }
696
697 res.field("layout", &self.inner.layout)
698 .field("shader_stages", &shader_stages)
699 .field("input_attachments", &self.inner.input_attachments)
700 .finish_non_exhaustive()
701 }
702}
703
704impl Eq for GraphicsPipeline {}
705
706impl Hash for GraphicsPipeline {
707 fn hash<H: Hasher>(&self, state: &mut H) {
708 Arc::as_ptr(&self.inner).hash(state);
709 }
710}
711
712impl PartialEq for GraphicsPipeline {
713 fn eq(&self, other: &Self) -> bool {
714 Arc::ptr_eq(&self.inner, &other.inner)
715 }
716}
717
718#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
722#[builder(
723 build_fn(private, name = "fallible_build"),
724 derive(Clone, Copy, Debug),
725 pattern = "owned"
726)]
727pub struct GraphicsPipelineInfo {
728 #[builder(default)]
731 pub alpha_to_coverage: bool,
732
733 #[builder(default)]
736 pub alpha_to_one: bool,
737
738 #[builder(default = "8192")]
761 pub bindless_descriptor_count: u32,
762
763 #[builder(default)]
768 pub blend: BlendInfo,
769
770 #[builder(default = "vk::CullModeFlags::BACK")]
774 pub cull_mode: vk::CullModeFlags,
775
776 #[builder(default = "vk::FrontFace::COUNTER_CLOCKWISE")]
780 pub front_face: vk::FrontFace,
781
782 #[builder(default, setter(into, strip_option))]
784 pub min_sample_shading: Option<OrderedFloat<f32>>,
785
786 #[builder(default = "vk::PolygonMode::FILL")]
790 pub polygon_mode: vk::PolygonMode,
791
792 #[builder(default = "vk::PrimitiveTopology::TRIANGLE_LIST")]
796 pub topology: vk::PrimitiveTopology,
797
798 #[builder(default = "SampleCount::Type1")]
804 pub samples: SampleCount,
805}
806
807impl GraphicsPipelineInfo {
808 pub fn builder() -> GraphicsPipelineInfoBuilder {
810 Default::default()
811 }
812
813 pub fn into_builder(self) -> GraphicsPipelineInfoBuilder {
815 GraphicsPipelineInfoBuilder {
816 alpha_to_coverage: Some(self.alpha_to_coverage),
817 alpha_to_one: Some(self.alpha_to_one),
818 bindless_descriptor_count: Some(self.bindless_descriptor_count),
819 blend: Some(self.blend),
820 cull_mode: Some(self.cull_mode),
821 front_face: Some(self.front_face),
822 min_sample_shading: Some(self.min_sample_shading),
823 polygon_mode: Some(self.polygon_mode),
824 topology: Some(self.topology),
825 samples: Some(self.samples),
826 }
827 }
828}
829
830impl Default for GraphicsPipelineInfo {
831 fn default() -> Self {
832 Self {
833 alpha_to_coverage: false,
834 alpha_to_one: false,
835 bindless_descriptor_count: 8192,
836 blend: BlendInfo::REPLACE,
837 cull_mode: vk::CullModeFlags::BACK,
838 front_face: vk::FrontFace::COUNTER_CLOCKWISE,
839 min_sample_shading: None,
840 polygon_mode: vk::PolygonMode::FILL,
841 topology: vk::PrimitiveTopology::TRIANGLE_LIST,
842 samples: SampleCount::Type1,
843 }
844 }
845}
846
847impl From<GraphicsPipelineInfoBuilder> for GraphicsPipelineInfo {
848 fn from(info: GraphicsPipelineInfoBuilder) -> Self {
849 info.build()
850 }
851}
852
853impl GraphicsPipelineInfoBuilder {
854 #[inline(always)]
856 pub fn build(self) -> GraphicsPipelineInfo {
857 self.fallible_build()
858 .expect("invalid graphics pipeline info")
859 }
860}
861
862#[derive(Debug)]
863pub(crate) struct GraphicsPipelineInner {
864 pub descriptor_bindings: DescriptorBindingMap,
865 pub descriptor_info: PipelineDescriptorInfo,
866 pub device: Device,
867 pub info: GraphicsPipelineInfo,
868 pub input_attachments: Box<[u32]>,
869 pub layout: vk::PipelineLayout,
870 pub multisample: MultisampleState,
871 pub push_constants: Box<[vk::PushConstantRange]>,
872 pub shader_stages: Box<[ShaderStage]>,
873 pub vertex_input: VertexInputState,
874}
875
876impl Drop for GraphicsPipelineInner {
877 #[profiling::function]
878 fn drop(&mut self) {
879 if panicking() {
880 return;
881 }
882
883 Device::try_clear_private_data_object_name(
884 &self.device,
885 vk::ObjectType::PIPELINE_LAYOUT,
886 self.layout,
887 );
888
889 unsafe {
890 self.device.destroy_pipeline_layout(self.layout, None);
891 }
892
893 for shader_stage in &mut self.shader_stages {
894 unsafe {
895 self.device.destroy_shader_module(shader_stage.module, None);
896 }
897 }
898 }
899}
900
901#[derive(Debug, Default)]
902pub(crate) struct MultisampleState {
903 pub alpha_to_coverage_enable: bool,
904 pub alpha_to_one_enable: bool,
905 pub flags: vk::PipelineMultisampleStateCreateFlags,
906 pub min_sample_shading: f32,
907 pub rasterization_samples: SampleCount,
908 pub sample_mask: Vec<u32>,
909 pub sample_shading_enable: bool,
910}
911
912#[derive(Debug)]
913pub(crate) struct ShaderStage {
914 pub flags: vk::ShaderStageFlags,
915 pub module: vk::ShaderModule,
916 pub name: CString, pub specialization: Option<SpecializationMap>,
918}
919
920#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
924pub struct StencilMode {
925 pub fail_op: vk::StencilOp,
927
928 pub pass_op: vk::StencilOp,
930
931 pub depth_fail_op: vk::StencilOp,
933
934 pub compare_op: vk::CompareOp,
936
937 pub compare_mask: u32,
939
940 pub write_mask: u32,
943
944 pub reference: u32,
947}
948
949impl StencilMode {
950 pub const IGNORE: Self = Self {
952 fail_op: vk::StencilOp::KEEP,
953 pass_op: vk::StencilOp::KEEP,
954 depth_fail_op: vk::StencilOp::KEEP,
955 compare_op: vk::CompareOp::NEVER,
956 compare_mask: 0,
957 write_mask: 0,
958 reference: 0,
959 };
960}
961
962impl Default for StencilMode {
963 fn default() -> Self {
964 Self::IGNORE
965 }
966}
967
968impl From<StencilMode> for vk::StencilOpState {
969 fn from(mode: StencilMode) -> Self {
970 Self {
971 fail_op: mode.fail_op,
972 pass_op: mode.pass_op,
973 depth_fail_op: mode.depth_fail_op,
974 compare_op: mode.compare_op,
975 compare_mask: mode.compare_mask,
976 write_mask: mode.write_mask,
977 reference: mode.reference,
978 }
979 }
980}
981
982#[derive(Clone, Debug, Default)]
983pub(crate) struct VertexInputState {
984 pub vertex_binding_descriptions: Vec<vk::VertexInputBindingDescription>,
985 pub vertex_attribute_descriptions: Vec<vk::VertexInputAttributeDescription>,
986}
987
988#[cfg(test)]
989mod test {
990 use super::*;
991
992 #[test]
993 pub fn blend_info() {
994 let info = BlendInfo::default();
995 let builder = info.into_builder().build();
996
997 assert_eq!(info, builder);
998 }
999
1000 #[test]
1001 pub fn blend_info_builder() {
1002 let info = BlendInfo::default();
1003 let builder = BlendInfoBuilder::default().build();
1004
1005 assert_eq!(info, builder);
1006 }
1007
1008 #[test]
1009 pub fn depth_stencil_info() {
1010 let info = DepthStencilInfo::default();
1011 let builder = info.into_builder().build();
1012
1013 assert_eq!(info, builder);
1014 }
1015
1016 #[test]
1017 pub fn depth_stencil_info_builder() {
1018 let info = DepthStencilInfo::default();
1019 let builder = DepthStencilInfoBuilder::default().build();
1020
1021 assert_eq!(info, builder);
1022 }
1023
1024 #[test]
1025 pub fn graphics_pipeline_info() {
1026 let info = GraphicsPipelineInfo::default();
1027 let builder = info.into_builder().build();
1028
1029 assert_eq!(info, builder);
1030 }
1031
1032 #[test]
1033 pub fn graphics_pipeline_info_builder() {
1034 let info = GraphicsPipelineInfo::default();
1035 let builder = GraphicsPipelineInfoBuilder::default().build();
1036
1037 assert_eq!(info, builder);
1038 }
1039}