Skip to main content

vulkayes_core/pipeline/
params.rs

1use ash::vk;
2
3unsafe impl crate::util::transparent::Transparent for vk::PipelineShaderStageCreateInfoBuilder<'_> {
4	type Target = vk::PipelineShaderStageCreateInfo;
5}
6unsafe impl crate::util::transparent::Transparent
7	for vk::PipelineColorBlendAttachmentStateBuilder<'_>
8{
9	type Target = vk::PipelineColorBlendAttachmentState;
10}
11
12unsafe_enum_variants! {
13	#[derive(Debug, Copy, Clone)]
14	enum PolygonModeInner {
15		pub Point => {
16			(vk::PolygonMode::POINT, vk::CullModeFlags::NONE, vk::FrontFace::COUNTER_CLOCKWISE, 1.0)
17		},
18		pub Line { width: f32 } => {
19			(vk::PolygonMode::LINE, vk::CullModeFlags::NONE, vk::FrontFace::COUNTER_CLOCKWISE, width)
20		},
21		pub LineDynamic => {
22			(vk::PolygonMode::LINE, vk::CullModeFlags::NONE, vk::FrontFace::COUNTER_CLOCKWISE, f32::NAN)
23		},
24		pub Fill {
25			cull_mode: vk::CullModeFlags,
26			front_face: vk::FrontFace
27		} => {
28			(vk::PolygonMode::FILL, cull_mode, front_face, 1.0)
29		},
30
31		{unsafe} pub Custom {
32			polygon_mode: vk::PolygonMode,
33			cull_mode: vk::CullModeFlags,
34			front_face: vk::FrontFace,
35			line_width: f32
36		} => {
37			(polygon_mode, cull_mode, front_face, line_width)
38		}
39	} as pub PolygonMode impl Into<(vk::PolygonMode, vk::CullModeFlags, vk::FrontFace, f32)>
40}
41impl Default for PolygonMode {
42	fn default() -> Self {
43		PolygonMode::Fill(vk::CullModeFlags::NONE, vk::FrontFace::COUNTER_CLOCKWISE)
44	}
45}
46
47#[derive(Debug, Copy, Clone)]
48pub enum DepthBias {
49	Disabled,
50	Enabled {
51		constant_factor: f32,
52		clamp: f32,
53		slope_factor: f32
54	},
55	Dynamic
56}
57impl Default for DepthBias {
58	fn default() -> Self {
59		DepthBias::Disabled
60	}
61}
62impl Into<(bool, f32, f32, f32)> for DepthBias {
63	fn into(self) -> (bool, f32, f32, f32) {
64		match self {
65			DepthBias::Disabled => (false, 0.0, 0.0, 0.0),
66			DepthBias::Enabled {
67				constant_factor,
68				clamp,
69				slope_factor
70			} => (true, constant_factor, clamp, slope_factor),
71			DepthBias::Dynamic => (true, f32::NAN, f32::NAN, f32::NAN)
72		}
73	}
74}
75
76#[derive(Debug, Copy, Clone)]
77pub enum SampleShading {
78	Disabled,
79	Enabled { min_sample_shading: f32 }
80}
81impl Default for SampleShading {
82	fn default() -> Self {
83		SampleShading::Disabled
84	}
85}
86impl Into<(bool, f32)> for SampleShading {
87	fn into(self) -> (bool, f32) {
88		match self {
89			SampleShading::Disabled => (false, 1.0),
90			SampleShading::Enabled { min_sample_shading } => (true, min_sample_shading)
91		}
92	}
93}
94
95#[derive(Debug, Copy, Clone)]
96pub enum DepthTest {
97	Disabled,
98	Enabled(vk::CompareOp),
99	EnabledReadonly(vk::CompareOp)
100}
101impl Default for DepthTest {
102	fn default() -> Self {
103		DepthTest::Enabled(vk::CompareOp::LESS)
104	}
105}
106impl Into<(bool, bool, vk::CompareOp)> for DepthTest {
107	fn into(self) -> (bool, bool, vk::CompareOp) {
108		match self {
109			DepthTest::Disabled => (false, false, vk::CompareOp::NEVER),
110			DepthTest::Enabled(op) => (true, true, op),
111			DepthTest::EnabledReadonly(op) => (true, false, op)
112		}
113	}
114}
115
116#[derive(Debug, Copy, Clone)]
117pub enum DepthBoundsTest {
118	Disabled,
119	Enabled(f32, f32),
120	Dynamic
121}
122impl Default for DepthBoundsTest {
123	fn default() -> DepthBoundsTest {
124		DepthBoundsTest::Disabled
125	}
126}
127impl Into<(bool, f32, f32)> for DepthBoundsTest {
128	fn into(self) -> (bool, f32, f32) {
129		match self {
130			DepthBoundsTest::Disabled => (false, 0.0, 0.0),
131			DepthBoundsTest::Enabled(min, max) => (true, min, max),
132			DepthBoundsTest::Dynamic => (true, f32::NAN, f32::NAN)
133		}
134	}
135}
136
137#[derive(Debug, Copy, Clone)]
138pub enum StencilTest {
139	Disabled,
140	Enabled {
141		fail_op: [vk::StencilOp; 2],
142		pass_op: [vk::StencilOp; 2],
143		depth_fail_op: [vk::StencilOp; 2],
144		compare_op: [vk::CompareOp; 2],
145		compare_mask: Option<[u32; 2]>,
146		write_mask: Option<[u32; 2]>,
147		reference: Option<[u32; 2]>
148	}
149}
150impl Default for StencilTest {
151	fn default() -> StencilTest {
152		StencilTest::Disabled
153	}
154}
155impl
156	Into<(
157		bool,
158		vk::StencilOpState,
159		vk::StencilOpState,
160		bool,
161		bool,
162		bool
163	)> for StencilTest
164{
165	fn into(
166		self
167	) -> (
168		bool,
169		vk::StencilOpState,
170		vk::StencilOpState,
171		bool,
172		bool,
173		bool
174	) {
175		match self {
176			StencilTest::Disabled => (
177				false,
178				Default::default(),
179				Default::default(),
180				false,
181				false,
182				false
183			),
184			StencilTest::Enabled {
185				fail_op,
186				pass_op,
187				depth_fail_op,
188				compare_op,
189				compare_mask,
190				write_mask,
191				reference
192			} => {
193				let cmp_mask = compare_mask.unwrap_or([0, 0]);
194				let wrt_mask = write_mask.unwrap_or([0, 0]);
195				let rfc = reference.unwrap_or([0, 0]);
196
197				(
198					true,
199					vk::StencilOpState {
200						fail_op: fail_op[0],
201						pass_op: pass_op[0],
202						depth_fail_op: depth_fail_op[0],
203						compare_op: compare_op[0],
204						compare_mask: cmp_mask[0],
205						write_mask: wrt_mask[0],
206						reference: rfc[0]
207					},
208					vk::StencilOpState {
209						fail_op: fail_op[1],
210						pass_op: pass_op[1],
211						depth_fail_op: depth_fail_op[1],
212						compare_op: compare_op[1],
213						compare_mask: cmp_mask[1],
214						write_mask: wrt_mask[1],
215						reference: rfc[1]
216					},
217					compare_mask.is_none(),
218					write_mask.is_none(),
219					reference.is_none()
220				)
221			}
222		}
223	}
224}
225
226#[derive(Debug, Copy, Clone)]
227pub enum BlendLogicOp {
228	Disabled,
229	Enabled(vk::LogicOp)
230}
231impl Default for BlendLogicOp {
232	fn default() -> BlendLogicOp {
233		BlendLogicOp::Disabled
234	}
235}
236impl Into<(bool, vk::LogicOp)> for BlendLogicOp {
237	fn into(self) -> (bool, vk::LogicOp) {
238		match self {
239			BlendLogicOp::Disabled => (false, Default::default()),
240			BlendLogicOp::Enabled(op) => (true, op)
241		}
242	}
243}
244
245/// Expands to a tuple of `(vk::Viewport, vk::Rect2D)` or into a tuple of `([vk::Viewport], [vk::Rect2D], bool, bool)`.
246///
247/// Syntax: `area offset? depth? scissor?`
248/// * `area` - expression: `[$w, $h]` specifying width and height of the viewport (in `f32`)
249/// * `offset?` - expression: `+ [$x, $y]` specifying offset of viewport, default: `[0.0f32, 0.0f32]`
250/// * `depth?` - expression: `: [$min, $max]` specifying minimum and maximum depth, default: `[0.0f32, 1.0f32]`
251/// * `scissor?` - expression: `@ [$x, $y, $width, $height]` specifying scissor region, default: `[0i32, 0i32, i32::MAX as u32, i32::MAX as u32]`
252///
253/// Example:
254/// ```
255/// # use vulkayes_core::viewport_scissor_expr;
256/// viewport_scissor_expr!(
257/// 	[100.0, 200.0] + [10.0, 20.0] : [0.0, 1.0] @ [0, 0, 100, 200]
258/// );
259/// ```
260#[macro_export]
261macro_rules! viewport_scissor_expr {
262	(
263		[
264			$(
265				dynamic @ [$sc_left: expr, $sc_top: expr, $sc_width: expr, $sc_height: expr]
266			),+ $(,)?
267		]
268	) => {
269		{
270			let viewports = [
271				$(
272					{
273						let _ = $sc_left; // hack for macro
274						$crate::ash::vk::Viewport::default()
275					}
276				),+
277			];
278
279			let scissors = [
280				$(
281					$crate::viewport_scissor_expr!([0.0, 0.0] @ [$sc_left, $sc_top, $sc_width, $sc_height]).1
282				),+
283			];
284
285			(viewports, scissors, true, false)
286		}
287	};
288
289	(
290		[
291			$(
292				[$width: expr, $height: expr] $(+ [$left: expr, $top: expr])? $(: [$near: expr, $far: expr])? @ dynamic
293			),+ $(,)?
294		]
295	) => {
296		{
297			let viewports = [
298				$(
299					$crate::viewport_scissor_expr!(
300						[$width, $height] $(+ [$left, $top])? $(: [$near, $far])?
301					).0
302				),+
303			];
304
305			let scissors = [
306				$(
307					{
308						let _ = $width; // hack for macro
309						$crate::ash::vk::Rect2D::default()
310					}
311				),+
312			];
313
314			(viewports, scissors, false, true)
315		}
316	};
317
318	(
319		dynamic[$count: expr]
320	) => {
321		{
322			let viewports = [$crate::ash::vk::Viewport::default(); $count];
323			let scissors = [$crate::ash::vk::Rect2D::default(); $count];
324
325			(viewports, scissors, true, true)
326		}
327	};
328
329	(
330		[
331			$(
332				[$width: expr, $height: expr]
333					$(+ [$left: expr, $top: expr])?
334					$(: [$near: expr, $far: expr])?
335					$(@ [$sc_left: expr, $sc_top: expr, $sc_width: expr, $sc_height: expr])?
336			),* $(,)?
337		]
338	) => {
339		{
340			let viewports = [
341				$(
342					$crate::viewport_scissor_expr!(
343						[$width, $height] $(+ [$left, $top])? $(: [$near, $far])?
344					).0
345				),*
346			];
347
348			let scissors = [
349				$(
350					$crate::viewport_scissor_expr!(
351						[$width, $height] $(+ [$left, $top])? $(: [$near, $far])? $(@ [$sc_left, $sc_top, $sc_width, $sc_height])?
352					).1
353				),*
354			];
355
356			(viewports, scissors, false, false)
357		}
358	};
359
360	(
361		[$width: expr, $height: expr]
362			$(+ [$left: expr, $top: expr])?
363			$(: [$near: expr, $far: expr])?
364			$(@ [$sc_left: expr, $sc_top: expr, $sc_width: expr, $sc_height: expr])?
365	) => {
366		{
367			let viewport = {
368				#[allow(unused_assignments, unused_mut)]
369				let mut x: f32 = 0.0;
370				#[allow(unused_assignments, unused_mut)]
371				let mut y: f32 = 0.0;
372				$(
373					x = $left;
374					y = $top;
375				)?
376
377				#[allow(unused_assignments)]
378				let width: f32 = $width;
379				#[allow(unused_assignments)]
380				let height: f32 = $height;
381
382				#[allow(unused_assignments, unused_mut)]
383				let mut min_depth: f32 = 0.0;
384				#[allow(unused_assignments, unused_mut)]
385				let mut max_depth: f32 = 1.0;
386				$(
387					min_depth = $near;
388					max_depth = $far;
389				)?
390
391				$crate::ash::vk::Viewport {
392					x,
393					y,
394					width,
395					height,
396					min_depth,
397					max_depth
398				}
399			};
400
401			let scissor = {
402				#[allow(unused_assignments, unused_mut)]
403				let mut x: i32 = 0;
404				#[allow(unused_assignments, unused_mut)]
405				let mut y: i32 = 0;
406
407				#[allow(unused_assignments, unused_mut)]
408				let mut width: u32 = i32::MAX as u32;
409				#[allow(unused_assignments, unused_mut)]
410				let mut height: u32 = i32::MAX as u32;
411
412				$(
413					x = $sc_left;
414					y = $sc_top;
415					width = $sc_width;
416					height = $sc_height;
417				)?
418
419				$crate::ash::vk::Rect2D {
420					offset: $crate::ash::vk::Offset2D {
421						x,
422						y
423					},
424					extent: $crate::ash::vk::Extent2D {
425						width,
426						height
427					}
428				}
429			};
430
431			(viewport, scissor)
432		}
433	};
434}
435
436/// Expands to `vk::PipelineColorBlendAttachmentStateBuilder`.
437///
438/// Syntax: `color : alpha & mask`
439/// * `color` - expression: `($src_factor) * src {$op} ($dst_factor) * dst` specifying the source and destination factors (`vk::BlendFactor`) and blending operation (`vk::BlendOp`).
440/// * `alpha` - expression: `($src_factor) * src {$op} ($dst_factor) * dst` specifying the source and destination factors (`vk::BlendFactor`) and blending operation (`vk::BlendOp`).
441/// * `mask` - value of type `vk::ColorComponentFlags`
442///
443/// The macro also accepts the token `disabled & mask`, which returns a builder with blending disabled.
444///
445/// Example:
446/// ```
447/// # use vulkayes_core::color_blend_state_expr;
448/// # use vulkayes_core::ash::vk;
449/// // Blends based on alpha, stores the new alpha, doesn't mask anything
450/// color_blend_state_expr!(
451/// 	(S * SRC_ALPHA) ADD (D * ONE_MINUS_SRC_ALPHA)
452/// 		: (S * ONE) SUBTRACT (D * ZERO)
453/// 		& vk::ColorComponentFlags::all()
454/// );
455/// // Disables blending, doesn't mask anything
456/// color_blend_state_expr!(
457/// 	disabled & vk::ColorComponentFlags::all()
458/// );
459/// // Same as the first one, but variables are expressions instead of identifiers.
460/// color_blend_state_expr!(
461/// 	(S * vk::BlendFactor::SRC_ALPHA) {vk::BlendOp::ADD} (D * vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
462/// 		: (S * vk::BlendFactor::ONE) {vk::BlendOp::SUBTRACT} (D * vk::BlendFactor::ZERO)
463/// 		& vk::ColorComponentFlags::all()
464/// );
465/// ```
466#[macro_export]
467macro_rules! color_blend_state_expr {
468	(
469		disabled & $color_write_mask: expr
470	) => {
471		$crate::ash::vk::PipelineColorBlendAttachmentState::builder().blend_enable(false)
472			.color_write_mask($color_write_mask)
473	};
474
475	(
476		(S * $src_color_blend_factor: ident) $color_blend_op: ident (D * $dst_color_blend_factor: ident)
477			: (S * $src_alpha_blend_factor: ident) $alpha_blend_op: ident (D * $dst_alpha_blend_factor: ident)
478			& $color_write_mask: expr
479	) => {
480		{
481			use $crate::ash::vk::{BlendFactor, BlendOp};
482
483			$crate::color_blend_state_expr!(
484				(S * BlendFactor::$src_color_blend_factor) {BlendOp::$color_blend_op} (D * BlendFactor::$dst_color_blend_factor)
485					: (S * BlendFactor::$src_alpha_blend_factor) {BlendOp::$color_blend_op} (D * BlendFactor::$dst_alpha_blend_factor)
486					& $color_write_mask
487			)
488		}
489	};
490
491	(
492		(S * $src_color_blend_factor: expr) {$color_blend_op: expr} (D * $dst_color_blend_factor: expr)
493			: (S * $src_alpha_blend_factor: expr) {$alpha_blend_op: expr} (D * $dst_alpha_blend_factor: expr)
494			& $color_write_mask: expr
495	) => {
496		$crate::ash::vk::PipelineColorBlendAttachmentState::builder().blend_enable(true)
497			.src_color_blend_factor($src_color_blend_factor)
498			.dst_color_blend_factor($dst_color_blend_factor)
499			.color_blend_op($color_blend_op)
500			.src_alpha_blend_factor($src_alpha_blend_factor)
501			.dst_alpha_blend_factor($dst_alpha_blend_factor)
502			.alpha_blend_op($alpha_blend_op)
503			.color_write_mask($color_write_mask)
504	};
505}
506
507/// Graphics pipeline creation macro that makes it easier to specify parameters.
508///
509/// This macro expands to an item. To use the generated `vk::GraphicsPipelineCreateInfoBuilder`,
510/// the variable expanded from `$create_info_variable_name` is introduced into the scope after calling this macro.
511///
512/// The builder is only valid for the lifetime of the calling scope because it borrows from variables declared inside
513/// this macro. Calling `build` on the builder and then returning it is undefined behavior!. TODO
514///
515/// The parameters are split into several sections grouping similar paramters. The following list shows
516/// separate sections, their fields and the types of arguments expected. `?` marks an optional parameter.
517///
518/// * **Shaders** - Parameters affecting shader stages, input descriptions and primitive topology.
519/// 	* `stages` - array of binding expressions: `module, entry?, spec? => point`:
520/// 		* `module` - value of type [`ShaderModule`](shader/struct.ShaderModule.html)
521/// 		* `entry?` - value of type [`ShaderEntryPoint`](shader/params/enum.ShaderEntryPoint.html), default: `ShaderEntryPoint::default()`
522/// 		* `spec?` - any value defining `fn specialization_info(&self) -> vk::SpecializationInfoBuilder`, default: unset (null pointer)
523/// 		* `point` -> value of type `vk::ShaderStageFlags`
524/// 	* `input` - tokens passed directly to [`vertex_input_description!`](macro.vertex_input_description.html) macro
525/// 	* `topology` - value of type `vk::PrimitiveTopology`
526/// 	* `primitive_restart?` - value of type `bool`, default: `false`
527/// * **Tessellation** - Parameters affecting tessellation.
528/// 	* `patch_control_points`? - value of type `u32`, default: `0`
529/// * **Viewport** - Parameters affecting viewports and scissors.
530/// 	* `viewports` - tokens passed directly to [`viewport_scissor_expr!`](macro.viewport_scissor_expr.html) macro
531/// * **Rasterization** - Parameters affecting rasterization, clipping and clamping.
532/// 	* `depth_clamp?` - value of type `bool`, default: `false`
533/// 	* `depth_clip?` - value of type `bool`, default: unset (extension struct not passed)
534/// 	* `discard?` - value of type `bool`, default: `false`
535/// 	* `polygon_mode` - value of type [`PolygonMode`](pipeline/params/struct.PolygonMode.html)
536/// 	* `depth_bias?` - value of type [`DepthBias`](pipeline/params/enum.DepthBias.html), default: `DepthBias::default()`
537/// * **Multisampling** - Parameters affecting multisampling.
538/// 	* `samples` - value of type `vk::SampleCountFlags`
539/// 	* `sample_shading?` - value of type [`SampleShading`](pipeline/params/enum.SampleShading.html), default: `SampleShading::default()`
540/// 	* `sample_mask?` - value that borrows as `&[u32]`, default: unset (null pointer)
541/// 	* `alpha_to_coverage?` - value of type `bool`, default: `false`
542/// 	* `alpha_to_one?` - value of type `bool`, default: `false`
543/// * **DepthStencil** - Parameters affecting depth and stencil tests.
544/// 	* `depth` - value of type [`DepthTest`](pipeline/params/enum.DepthTest.html)
545/// 	* `depth_bounds`? - value of type [`DepthBoundsTest`](pipeline/params/enum.DepthBoundsTest.html), default: `DepthBoundsTest::default()`
546/// 	* `stencil`? - value of type [`StencilTest`](pipeline/params/enum.StencilTest.html), default: `StencilTest::default()`
547/// * **ColorBlend** - Parameters affecting color blending and operations.
548/// 	* `logic_op?` - value of type [`BlendLogicOp`](pipeline/params/enum.BlendLogicOp.html), default: `BlendLogicOp::default()`
549/// 	* `attachments` -  array of blending expressions passed directly to [`color_blend_state_expr!`](macro.color_blend_state_expr.html) macro
550/// 	* `blend_constants?` - value of type `Option<[f32; 4]>`, default: `Some([0.0; 4])`, `None` means to enable dynamic state
551/// * **Deps** - Parameters needed as dependencies.
552/// 	* `layout` - any value defining `fn handle(&self) -> vk::PipelineLayout`
553/// 	* `render_pass` - any value defining `fn handle(&self) -> vk::RenderPass`
554/// 	* `subpass?` - value of type `u32`, default: `0`
555///
556/// Note that some sections are optional altogether, however, not specifying a section means it won't be included at all in the
557/// create info and no defaults will be provided (the struct pointer will be null). Commonly only the `Tessellation` section is left out,
558/// but with rasterization disabled the `Viewport`, `Multisampling`, `DepthStencil` and `ColorBlend` sections can be left out as well.
559/// `DepthStencil` and `ColorBlend` also have additional cases where they can be left out: <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkGraphicsPipelineCreateInfo.html>.
560#[macro_export]
561macro_rules! create_graphics_pipeline {
562	(
563		@Shaders($output_builder: expr)
564		stages: [
565			$(
566				$stage: expr $(, $entry_name: expr $(, $specialization: expr)?)? => $stage_type: expr
567			),* $(,)?
568		] $(,)?
569		input: {
570			$($input_tt: tt)*
571		} $(,)?
572		topology: $topology: expr
573		$(, primitive_restart: $primitive_restart: expr)?
574		$(,)?
575	) => {
576		let specialization_infos = [
577			$(
578				{
579					let mut info = None::<$crate::ash::vk::SpecializationInfoBuilder>;
580					$(
581						$(
582							info = Some($specialization.specialization_info());
583						)?
584					)?
585
586					info
587				}
588			),*
589		];
590		let _: &[Option<$crate::ash::vk::SpecializationInfoBuilder>] = &specialization_infos;
591
592		#[allow(unused_variables, unused_mut)]
593		let mut counter: usize = 0;
594		let stages = [
595			$(
596				{
597					let mut entry_name: $crate::shader::params::ShaderEntryPoint = Default::default();
598					$(
599						entry_name = $entry_name;
600					)?
601
602					counter += 1;
603					$stage.stage_create_info(
604						$stage_type,
605						entry_name,
606						specialization_infos[counter - 1].as_ref()
607					)
608				}
609			),*
610		];
611		let _: &[$crate::ash::vk::PipelineShaderStageCreateInfoBuilder] = &stages;
612
613		let (shader_input_bindings, shader_input_attributes) = $crate::vertex_input_description!(
614			$($input_tt)*
615		);
616		let input_assembly = $crate::ash::vk::PipelineInputAssemblyStateCreateInfo::builder()
617			.topology($topology)
618			.primitive_restart_enable(
619				{
620					#[allow(unused_mut)]
621					let mut restart = false;
622					$(
623						restart = $primitive_restart;
624					)?
625
626					restart
627				}
628			)
629		;
630
631		let input_state = $crate::ash::vk::PipelineVertexInputStateCreateInfo::builder()
632			.vertex_binding_descriptions(&shader_input_bindings)
633			.vertex_attribute_descriptions(&shader_input_attributes)
634		;
635
636		$output_builder = $output_builder
637			.stages(
638				$crate::util::transparent::Transparent::transmute_slice(&stages)
639			)
640			.vertex_input_state(&input_state)
641			.input_assembly_state(&input_assembly)
642		;
643	};
644
645	(
646		@Tessellation($output_builder: expr)
647		patch_control_points: $patch_control_points: expr
648		$(, domain_origin: $domain_origin: expr)?
649	) => {
650		#[allow(unused_mut)]
651		let mut builder = $crate::ash::vk::PipelineTessellationStateCreateInfo::builder()
652			.patch_control_points($patch_control_points)
653		;
654		$(
655			let mut domain_origin_info = $crate::ash::vk::PipelineTessellationDomainOriginStateCreateInfo::builder()
656				.domain_origin($domain_origin)
657			;
658			builder = builder.push_next(&mut domain_origin_info);
659		)?
660
661		$output_builder = $output_builder
662			.tessellation_state(&builder)
663		;
664	};
665
666	(
667		@Viewport($output_builder: expr, $dynamic_info: expr)
668		viewports: {
669			$($viewports_tt: tt)+
670		} $(,)?
671	) => {
672		let (viewports, scissors, dynamic_viewport, dynamic_scissors) = $crate::viewport_scissor_expr!(
673			$($viewports_tt)+
674		);
675
676		let builder = $crate::ash::vk::PipelineViewportStateCreateInfo::builder()
677			.viewports(&viewports)
678			.scissors(&scissors)
679		;
680
681		$output_builder = $output_builder.viewport_state(&builder);
682
683		if dynamic_viewport {
684			$dynamic_info.push($crate::ash::vk::DynamicState::VIEWPORT);
685		}
686		if dynamic_scissors {
687			$dynamic_info.push($crate::ash::vk::DynamicState::SCISSOR);
688		}
689	};
690
691	(
692		@Rasterization($output_builder: expr, $dynamic_info: expr)
693		$(depth_clamp: $depth_clamp: expr,)?
694		$(depth_clip: $depth_clip: expr,)?
695		$(discard: $discard: expr,)?
696		polygon_mode: $polygon_mode: expr
697		$(, depth_bias: $depth_bias: expr)?
698		$(,)?
699	) => {
700		#[allow(unused_assignments, unused_mut)]
701		let mut builder = $crate::ash::vk::PipelineRasterizationStateCreateInfo::builder();
702		$(
703			let mut depth_clip = $crate::ash::vk::PipelineRasterizationDepthClipStateCreateInfoEXT::builder().depth_clip_enable($depth_clip);
704			builder = builder.push_next(&mut depth_clip);
705		)?
706
707		#[allow(unused_assignments, unused_mut)]
708		let mut depth_clamp = false;
709		$(
710			depth_clamp = $depth_clamp;
711		)?
712		#[allow(unused_assignments, unused_mut)]
713		let mut discard = false;
714		$(
715			discard = $discard;
716		)?
717
718		let polygon_info: $crate::pipeline::params::PolygonMode = $polygon_mode;
719		let (polygon_mode, cull_mode, front_face, line_width) = polygon_info.into();
720
721		#[allow(unused_assignments, unused_mut)]
722		let mut depth_bias: $crate::pipeline::params::DepthBias = Default::default();
723		$(
724			depth_bias = $depth_bias;
725		)?
726		let (depth_bias_enable, depth_bias_constant_factor, depth_bias_clamp, depth_bias_slope_factor) = depth_bias.into();
727
728		builder = builder
729			.depth_clamp_enable(depth_clamp)
730			.rasterizer_discard_enable(discard)
731			.polygon_mode(polygon_mode)
732			.cull_mode(cull_mode)
733			.front_face(front_face)
734			.depth_bias_enable(depth_bias_enable)
735			.depth_bias_constant_factor(depth_bias_constant_factor)
736			.depth_bias_clamp(depth_bias_clamp)
737			.depth_bias_slope_factor(depth_bias_slope_factor)
738			.line_width(line_width)
739		;
740
741		$output_builder = $output_builder.rasterization_state(&builder);
742
743		if line_width.is_nan() {
744			$dynamic_info.push($crate::ash::vk::DynamicState::LINE_WIDTH);
745		}
746		if depth_bias_enable && (depth_bias_constant_factor.is_nan() || depth_bias_clamp.is_nan() || depth_bias_slope_factor.is_nan()) {
747			$dynamic_info.push($crate::ash::vk::DynamicState::DEPTH_BIAS);
748		}
749	};
750
751	(
752		@Multisampling($output_builder: expr)
753		samples: $samples: expr
754		$(, sample_shading: $sample_shading: expr)?
755		$(, sample_mask: $sample_mask: expr)?
756		$(, alpha_to_coverage: $alpha_to_coverage: expr)?
757		$(, alpha_to_one: $alpha_to_one: expr)?
758		$(,)?
759	) => {
760		#[allow(unused_assignments, unused_mut)]
761		let mut sample_shading = $crate::pipeline::params::SampleShading::default();
762		$(
763			sample_shading = $sample_shading;
764		)?
765		let (sample_shading_enable, min_sample_shading) = sample_shading.into();
766
767		#[allow(unused_assignments, unused_mut)]
768		let mut alpha_to_coverage = false;
769		$(
770			alpha_to_coverage = $alpha_to_coverage;
771		)?
772		#[allow(unused_assignments, unused_mut)]
773		let mut alpha_to_one = false;
774		$(
775			alpha_to_one = $alpha_to_one;
776		)?
777
778		#[allow(unused_assignments, unused_mut)]
779		let mut builder = $crate::ash::vk::PipelineMultisampleStateCreateInfo::builder()
780			.rasterization_samples($samples)
781			.sample_shading_enable(sample_shading_enable)
782			.min_sample_shading(min_sample_shading)
783			.alpha_to_coverage_enable(alpha_to_coverage)
784			.alpha_to_one_enable(alpha_to_one)
785		;
786
787		$(
788			let sample_mask_array = $sample_mask;
789			let sample_mask_array_slice: &[u32] = $sample_mask_array;
790			builder = builder.sample_mask(sample_mask_array_slice);
791		)?
792
793		$output_builder = $output_builder.multisample_state(&builder);
794	};
795
796	(
797		@DepthStencil($output_builder: expr, $dynamic_info: expr)
798		depth: $depth_test: expr
799		$(, depth_bounds: $depth_bounds_test: expr)?
800		$(, stencil: $stencil_test: expr)?
801		$(,)?
802	) => {
803		let depth_test: $crate::pipeline::params::DepthTest = $depth_test;
804		let (depth_test_enable, depth_write_enable, depth_compare_op) = depth_test.into();
805
806		#[allow(unused_assignments, unused_mut)]
807		let mut depth_bounds_test = $crate::pipeline::params::DepthBoundsTest::default();
808		$(
809			depth_bounds_test = $depth_bounds_test;
810		)?
811		let (depth_bounds_test_enable, min_depth_bounds, max_depth_bounds) = depth_bounds_test.into();
812
813		#[allow(unused_assignments, unused_mut)]
814		let mut stencil_test = $crate::pipeline::params::StencilTest::default();
815		$(
816			stencil_test = $stencil_test;
817		)?
818		let (stencil_test_enable, front, back, stencil_comare_dynamic, stencil_write_dynamic, stencil_reference_dynamic) = stencil_test.into();
819
820		let builder = $crate::ash::vk::PipelineDepthStencilStateCreateInfo::builder()
821			.depth_test_enable(depth_test_enable)
822			.depth_write_enable(depth_write_enable)
823			.depth_compare_op(depth_compare_op)
824			.depth_bounds_test_enable(depth_bounds_test_enable)
825			.stencil_test_enable(stencil_test_enable)
826			.front(front)
827			.back(back)
828			.min_depth_bounds(min_depth_bounds)
829			.max_depth_bounds(max_depth_bounds)
830		;
831
832		$output_builder = $output_builder
833			.depth_stencil_state(&builder)
834		;
835
836		if depth_bounds_test_enable && (min_depth_bounds.is_nan() || max_depth_bounds.is_nan()) {
837			$dynamic_info.push($crate::ash::vk::DynamicState::DEPTH_BOUNDS);
838		}
839
840		if stencil_test_enable {
841			if stencil_comare_dynamic {
842				$dynamic_info.push($crate::ash::vk::DynamicState::STENCIL_COMPARE_MASK);
843			}
844			if stencil_write_dynamic {
845				$dynamic_info.push($crate::ash::vk::DynamicState::STENCIL_WRITE_MASK);
846			}
847			if stencil_reference_dynamic {
848				$dynamic_info.push($crate::ash::vk::DynamicState::STENCIL_REFERENCE);
849			}
850		}
851	};
852
853	(
854		@ColorBlend($output_builder: expr, $dynamic_info: expr)
855		$(logic_op: $logic_op: expr,)?
856		attachments: [
857			$(
858				{ $($attachment_tt: tt)+ }
859			),*
860			$(,)?
861		]
862		$(, blend_constants: $blend_constants: expr)?
863		$(,)?
864	) => {
865		let attachments = [
866			$(
867				$crate::color_blend_state_expr!($($attachment_tt)+)
868			),*
869		];
870
871		#[allow(unused_assignments, unused_mut)]
872		let mut logic_op: $crate::pipeline::params::BlendLogicOp = Default::default();
873		$(
874			logic_op = $logic_op;
875		)?
876		let (logic_op_enable, logic_op) = logic_op.into();
877
878		#[allow(unused_assignments, unused_mut)]
879		let mut blend_constants: Option<[f32; 4]> = Some([0.0; 4]);
880		$(
881			blend_constants = $blend_constants;
882		)?
883		let blend_constants_value = blend_constants.unwrap_or([0.0; 4]);
884
885		let builder = $crate::ash::vk::PipelineColorBlendStateCreateInfo::builder()
886			.logic_op_enable(logic_op_enable)
887			.logic_op(logic_op)
888			.attachments(
889				$crate::util::transparent::Transparent::transmute_slice(&attachments)
890			)
891			.blend_constants(blend_constants_value)
892		;
893
894		$output_builder = $output_builder
895			.color_blend_state(&builder)
896		;
897
898		if blend_constants.is_none() {
899			$dynamic_info.push($crate::ash::vk::DynamicState::BLEND_CONSTANTS);
900		}
901	};
902
903	(
904		@Deps($output_builder: expr)
905		layout: $layout: expr,
906		render_pass: $render_pass: expr
907		$(, subpass: $subpass: expr)?
908		$(,)?
909	) => {
910		let layout: $crate::ash::vk::PipelineLayout = $layout.handle();
911		let render_pass: $crate::ash::vk::RenderPass = $render_pass.handle();
912
913		#[allow(unused_assignments, unused_mut)]
914		let mut subpass: u32 = 0;
915		$(
916			subpass = $subpass;
917		)?
918
919		$output_builder = $output_builder
920			.layout(layout)
921			.render_pass(render_pass)
922			.subpass(subpass)
923		;
924	};
925
926	(
927		let $create_info_variable_name: ident;
928
929		Shaders {
930			$($shaders_tt: tt)+
931		}
932
933		$(
934			Tessellation {
935				$($tessellation_tt: tt)+
936			}
937		)?
938
939		$(
940			Viewport {
941				$($viewport_tt: tt)+
942			}
943		)?
944
945		Rasterization {
946			$($rasterization_tt: tt)+
947		}
948
949		$(
950			Multisampling {
951				$($multisampling_tt: tt)+
952			}
953		)?
954
955		$(
956			DepthStencil {
957				$($depth_stencil_tt: tt)+
958			}
959		)?
960
961		$(
962			ColorBlend {
963				$($color_blend_tt: tt)+
964			}
965		)?
966
967		Deps {
968			$($deps_tt: tt)+
969		}
970	) => {
971		struct DynamicInfo {
972			index: usize,
973			array: [$crate::ash::vk::DynamicState; 9]
974		}
975		impl DynamicInfo {
976			pub fn new() -> Self {
977				DynamicInfo {
978					index: 0,
979					array: Default::default()
980				}
981			}
982
983			pub fn push(&mut self, value: $crate::ash::vk::DynamicState) {
984				debug_assert!(self.index < self.array.len());
985				self.array[self.index] = value;
986				self.index += 1;
987			}
988
989			pub fn as_slice(&self) -> &[$crate::ash::vk::DynamicState] {
990				&self.array[..self.index]
991			}
992		}
993
994		#[allow(unused_mut)]
995		let mut dynamic_info = DynamicInfo::new();
996		let mut builder = $crate::ash::vk::GraphicsPipelineCreateInfo::builder();
997
998		$crate::create_graphics_pipeline!(
999			@Shaders(builder)
1000			$($shaders_tt)+
1001		);
1002
1003		$(
1004			$crate::create_graphics_pipeline!(
1005				@Tessellation(builder)
1006				$($tessellation_tt)*
1007			);
1008		)?
1009
1010		$(
1011			$crate::create_graphics_pipeline!(
1012				@Viewport(builder, dynamic_info)
1013				$($viewport_tt)+
1014			);
1015		)?
1016
1017		$crate::create_graphics_pipeline!(
1018			@Rasterization(builder, dynamic_info)
1019			$($rasterization_tt)+
1020		);
1021
1022		$(
1023			$crate::create_graphics_pipeline!(
1024				@Multisampling(builder)
1025				$($multisampling_tt)+
1026			);
1027		)?
1028
1029		$(
1030			$crate::create_graphics_pipeline!(
1031				@DepthStencil(builder, dynamic_info)
1032				$($depth_stencil_tt)+
1033			);
1034		)?
1035
1036		$(
1037			$crate::create_graphics_pipeline!(
1038				@ColorBlend(builder, dynamic_info)
1039				$($color_blend_tt)+
1040			);
1041		)?
1042
1043		$crate::create_graphics_pipeline!(
1044			@Deps(builder)
1045			$($deps_tt)+
1046		);
1047
1048		let dynamic_state;
1049		if dynamic_info.as_slice().len() > 0 {
1050			dynamic_state = $crate::ash::vk::PipelineDynamicStateCreateInfo::builder()
1051				.dynamic_states(dynamic_info.as_slice())
1052			;
1053			builder = builder.dynamic_state(&dynamic_state);
1054		}
1055
1056		// Final builder
1057		let $create_info_variable_name = builder;
1058	}
1059}
1060
1061#[cfg(test)]
1062mod test {
1063	use ash::vk as vvk;
1064
1065	#[test]
1066	#[ignore]
1067	fn test_graphics_pipeline_params() {
1068		offsetable_struct! {
1069			pub struct Vertex {
1070				position: [f32; 3],
1071				color: u32
1072			} repr(C) as VertexOffsets
1073		}
1074		#[repr(C)]
1075		struct Normal {
1076			normal: [f32; 3]
1077		}
1078
1079		struct LayoutHandle;
1080		impl LayoutHandle {
1081			fn handle(&self) -> vvk::PipelineLayout {
1082				vvk::PipelineLayout::null()
1083			}
1084		}
1085
1086		struct RenderPassHandle;
1087		impl RenderPassHandle {
1088			fn handle(&self) -> vvk::RenderPass {
1089				vvk::RenderPass::null()
1090			}
1091		}
1092
1093		create_graphics_pipeline! {
1094			let create_info;
1095
1096			Shaders {
1097				stages: []
1098				input: {
1099					Vertex {
1100						.position => layout(location = 0) in vec3 position;
1101						.color => layout(location = 2) in int color;
1102					}
1103					Normal {
1104						=> layout(location = 1) in vec3 normal;
1105					}
1106				}
1107				topology: vvk::PrimitiveTopology::TRIANGLE_LIST
1108			}
1109
1110			Tessellation {
1111				patch_control_points: 0
1112			}
1113
1114			Viewport {
1115				viewports: {
1116					[
1117						dynamic @ [0, 0, i32::MAX as u32, i32::MAX as u32]
1118					]
1119				}
1120			}
1121
1122			Rasterization {
1123				polygon_mode: super::PolygonMode::LineDynamic(),
1124				depth_bias: super::DepthBias::Dynamic
1125			}
1126
1127			Multisampling {
1128				samples: vvk::SampleCountFlags::TYPE_1
1129			}
1130
1131			DepthStencil {
1132				depth: Default::default(),
1133				depth_bounds: super::DepthBoundsTest::Dynamic,
1134				stencil: super::StencilTest::Enabled {
1135					fail_op: Default::default(),
1136					pass_op: Default::default(),
1137					depth_fail_op: Default::default(),
1138					compare_op: Default::default(),
1139					compare_mask: None,
1140					write_mask: None,
1141					reference: None
1142				}
1143			}
1144
1145			ColorBlend {
1146				logic_op: super::BlendLogicOp::default(),
1147				attachments: [
1148					{
1149						(S * SRC_ALPHA) ADD (D * ONE_MINUS_SRC_ALPHA)
1150							: (S * ONE) SUBTRACT (D * ZERO)
1151							& vvk::ColorComponentFlags::all()
1152					},
1153					{ disabled & vvk::ColorComponentFlags::all() }
1154				],
1155				blend_constants: None
1156			}
1157
1158			Deps {
1159				layout: LayoutHandle,
1160				render_pass: RenderPassHandle
1161			}
1162		};
1163
1164		macro_rules! dbg_it {
1165			(
1166				$base: expr;
1167				$(
1168					$field: ident[$len: literal]$({ $($rec_tt: tt)+ })?
1169				),+ $(,)?
1170			) => {
1171				$(
1172					if $base.$field == std::ptr::null() {
1173						eprintln!(
1174							"{} = null",
1175							stringify!($field)
1176						);
1177					} else {
1178						#[allow(unused_unsafe)]
1179						unsafe {
1180							for x in 0 .. $len {
1181								let field = *($base.$field.add(x));
1182								eprintln!(
1183									"[{:?}] {}[{}] = {:#?}",
1184									$base.$field.add(x),
1185									stringify!($field), x,
1186									field
1187								);
1188								$(
1189									dbg_it!(
1190										field;
1191										$($rec_tt)+
1192									);
1193								)?
1194							}
1195						}
1196						eprintln!("");
1197					}
1198				)+
1199			}
1200		}
1201
1202		dbg!(create_info.flags);
1203		dbg_it!(
1204			create_info;
1205
1206			p_stages[0],
1207			p_vertex_input_state[1]{p_vertex_binding_descriptions[2],p_vertex_attribute_descriptions[3]},
1208			p_input_assembly_state[1],
1209
1210			p_tessellation_state[1],
1211
1212			p_viewport_state[1]{p_viewports[2],p_scissors[2]},
1213
1214			p_rasterization_state[1],
1215
1216			p_multisample_state[1],
1217
1218			p_depth_stencil_state[1],
1219
1220			p_color_blend_state[1]{p_attachments[2]},
1221
1222			p_dynamic_state[1]{p_dynamic_states[9]}
1223		);
1224	}
1225}