1 // Copyright (c) 2017 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 // TODO: graphics pipeline params are deprecated, but are still the primary implementation in order
11 // to avoid duplicating code, so we hide the warnings for now
12 #![allow(deprecated)]
13 
14 use super::{
15     color_blend::{
16         AttachmentBlend, ColorBlendAttachmentState, ColorBlendState, ColorComponents, LogicOp,
17     },
18     depth_stencil::{DepthStencilState, StencilOps},
19     discard_rectangle::DiscardRectangleState,
20     input_assembly::{InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass},
21     multisample::MultisampleState,
22     rasterization::{
23         CullMode, DepthBiasState, FrontFace, LineRasterizationMode, PolygonMode, RasterizationState,
24     },
25     render_pass::{PipelineRenderPassType, PipelineRenderingCreateInfo},
26     tessellation::TessellationState,
27     vertex_input::{
28         VertexDefinition, VertexInputAttributeDescription, VertexInputBindingDescription,
29         VertexInputState,
30     },
31     viewport::{Scissor, Viewport, ViewportState},
32     GraphicsPipeline, GraphicsPipelineCreationError,
33 };
34 use crate::{
35     descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutCreateInfo},
36     device::{Device, DeviceOwned},
37     format::{FormatFeatures, NumericType},
38     image::ImageAspects,
39     pipeline::{
40         cache::PipelineCache,
41         graphics::{
42             color_blend::BlendFactor,
43             depth_stencil::{DepthBoundsState, DepthState, StencilOpState, StencilState},
44             vertex_input::VertexInputRate,
45         },
46         layout::{PipelineLayoutCreateInfo, PushConstantRange},
47         DynamicState, PartialStateMode, PipelineLayout, StateMode,
48     },
49     shader::{
50         DescriptorBindingRequirements, EntryPoint, FragmentShaderExecution, FragmentTestsStages,
51         ShaderExecution, ShaderScalarType, ShaderStage, SpecializationConstants,
52         SpecializationMapEntry,
53     },
54     DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
55 };
56 use ahash::HashMap;
57 use smallvec::SmallVec;
58 use std::{
59     collections::hash_map::Entry,
60     mem::{size_of_val, MaybeUninit},
61     ptr, slice,
62     sync::Arc,
63 };
64 
65 /// Prototype for a `GraphicsPipeline`.
66 #[derive(Debug)]
67 pub struct GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> {
68     render_pass: Option<PipelineRenderPassType>,
69     cache: Option<Arc<PipelineCache>>,
70 
71     vertex_shader: Option<(EntryPoint<'vs>, Vss)>,
72     tessellation_shaders: Option<TessellationShaders<'tcs, 'tes, Tcss, Tess>>,
73     geometry_shader: Option<(EntryPoint<'gs>, Gss)>,
74     fragment_shader: Option<(EntryPoint<'fs>, Fss)>,
75 
76     vertex_input_state: Vdef,
77     input_assembly_state: InputAssemblyState,
78     tessellation_state: TessellationState,
79     viewport_state: ViewportState,
80     discard_rectangle_state: DiscardRectangleState,
81     rasterization_state: RasterizationState,
82     multisample_state: MultisampleState,
83     depth_stencil_state: DepthStencilState,
84     color_blend_state: ColorBlendState,
85 }
86 
87 // Additional parameters if tessellation is used.
88 #[derive(Clone, Debug)]
89 struct TessellationShaders<'tcs, 'tes, Tcss, Tess> {
90     control: (EntryPoint<'tcs>, Tcss),
91     evaluation: (EntryPoint<'tes>, Tess),
92 }
93 
94 impl
95     GraphicsPipelineBuilder<
96         'static,
97         'static,
98         'static,
99         'static,
100         'static,
101         VertexInputState,
102         (),
103         (),
104         (),
105         (),
106         (),
107     >
108 {
109     /// Builds a new empty builder.
new() -> Self110     pub(super) fn new() -> Self {
111         GraphicsPipelineBuilder {
112             render_pass: None,
113             cache: None,
114 
115             vertex_shader: None,
116             tessellation_shaders: None,
117             geometry_shader: None,
118             fragment_shader: None,
119 
120             vertex_input_state: Default::default(),
121             input_assembly_state: Default::default(),
122             tessellation_state: Default::default(),
123             viewport_state: Default::default(),
124             discard_rectangle_state: Default::default(),
125             rasterization_state: Default::default(),
126             multisample_state: Default::default(),
127             depth_stencil_state: Default::default(),
128             color_blend_state: Default::default(),
129         }
130     }
131 }
132 
133 #[derive(Clone, Copy, Debug)]
134 struct Has {
135     vertex_input_state: bool,
136     pre_rasterization_shader_state: bool,
137     tessellation_state: bool,
138     viewport_state: bool,
139     fragment_shader_state: bool,
140     depth_stencil_state: bool,
141     fragment_output_state: bool,
142     color_blend_state: bool,
143 }
144 
145 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
146     GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
147 where
148     Vdef: VertexDefinition,
149     Vss: SpecializationConstants,
150     Tcss: SpecializationConstants,
151     Tess: SpecializationConstants,
152     Gss: SpecializationConstants,
153     Fss: SpecializationConstants,
154 {
155     /// Builds the graphics pipeline, using an inferred a pipeline layout.
156     #[inline]
build( self, device: Arc<Device>, ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>157     pub fn build(
158         self,
159         device: Arc<Device>,
160     ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
161         self.with_auto_layout(device, |_| {})
162     }
163 
164     /// The same as `new`, but allows you to provide a closure that is given a mutable reference to
165     /// the inferred descriptor set definitions. This can be used to make changes to the layout
166     /// before it's created, for example to add dynamic buffers or immutable samplers.
with_auto_layout<F>( self, device: Arc<Device>, func: F, ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> where F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),167     pub fn with_auto_layout<F>(
168         self,
169         device: Arc<Device>,
170         func: F,
171     ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>
172     where
173         F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
174     {
175         let (set_layout_create_infos, push_constant_ranges) = {
176             let stages: SmallVec<[&EntryPoint<'_>; 5]> = [
177                 self.vertex_shader.as_ref().map(|s| &s.0),
178                 self.tessellation_shaders.as_ref().map(|s| &s.control.0),
179                 self.tessellation_shaders.as_ref().map(|s| &s.evaluation.0),
180                 self.geometry_shader.as_ref().map(|s| &s.0),
181                 self.fragment_shader.as_ref().map(|s| &s.0),
182             ]
183             .into_iter()
184             .flatten()
185             .collect();
186 
187             // Produce `DescriptorBindingRequirements` for each binding, by iterating over all
188             // shaders and adding the requirements of each.
189             let mut descriptor_binding_requirements: HashMap<
190                 (u32, u32),
191                 DescriptorBindingRequirements,
192             > = HashMap::default();
193 
194             for (loc, reqs) in stages
195                 .iter()
196                 .flat_map(|shader| shader.descriptor_binding_requirements())
197             {
198                 match descriptor_binding_requirements.entry(loc) {
199                     Entry::Occupied(entry) => {
200                         // Previous shaders already added requirements, so we merge requirements of
201                         // the current shader into the requirements of the previous one.
202                         entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
203                     }
204                     Entry::Vacant(entry) => {
205                         // No previous shader had this descriptor yet, so we just insert the
206                         // requirements.
207                         entry.insert(reqs.clone());
208                     }
209                 }
210             }
211 
212             // Build a description of a descriptor set layout from the shader requirements, then
213             // feed it to the user-provided closure to allow tweaking.
214             let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
215                 descriptor_binding_requirements
216                     .iter()
217                     .map(|(&loc, reqs)| (loc, reqs)),
218             );
219             func(&mut set_layout_create_infos);
220 
221             // We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
222             // e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
223             // Vertex and a subrange available to Fragment, like [0, 8)
224             let mut range_map = HashMap::default();
225             for stage in stages.iter() {
226                 if let Some(range) = stage.push_constant_requirements() {
227                     match range_map.entry((range.offset, range.size)) {
228                         Entry::Vacant(entry) => {
229                             entry.insert(range.stages);
230                         }
231                         Entry::Occupied(mut entry) => {
232                             *entry.get_mut() = *entry.get() | range.stages;
233                         }
234                     }
235                 }
236             }
237             let push_constant_ranges: Vec<_> = range_map
238                 .iter()
239                 .map(|((offset, size), stages)| PushConstantRange {
240                     stages: *stages,
241                     offset: *offset,
242                     size: *size,
243                 })
244                 .collect();
245 
246             (set_layout_create_infos, push_constant_ranges)
247         };
248 
249         let set_layouts = set_layout_create_infos
250             .into_iter()
251             .map(|desc| DescriptorSetLayout::new(device.clone(), desc))
252             .collect::<Result<Vec<_>, _>>()?;
253         let pipeline_layout = PipelineLayout::new(
254             device.clone(),
255             PipelineLayoutCreateInfo {
256                 set_layouts,
257                 push_constant_ranges,
258                 ..Default::default()
259             },
260         )
261         .unwrap();
262         self.with_pipeline_layout(device, pipeline_layout)
263     }
264 
265     /// Builds the graphics pipeline.
266     ///
267     /// Does the same as `build`, except that `build` automatically builds the pipeline layout
268     /// object corresponding to the union of your shaders while this function allows you to specify
269     /// the pipeline layout.
270     #[inline]
with_pipeline_layout( mut self, device: Arc<Device>, pipeline_layout: Arc<PipelineLayout>, ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>271     pub fn with_pipeline_layout(
272         mut self,
273         device: Arc<Device>,
274         pipeline_layout: Arc<PipelineLayout>,
275     ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
276         let vertex_input_state = self
277             .vertex_input_state
278             .definition(self.vertex_shader.as_ref().unwrap().0.input_interface())?;
279 
280         // If there is one element, duplicate it for all attachments.
281         // TODO: this is undocumented and only exists for compatibility with some of the
282         // deprecated builder methods. Remove it when those methods are gone.
283         if self.color_blend_state.attachments.len() == 1 {
284             let color_attachment_count =
285                 match self.render_pass.as_ref().expect("Missing render pass") {
286                     PipelineRenderPassType::BeginRenderPass(subpass) => {
287                         subpass.subpass_desc().color_attachments.len()
288                     }
289                     PipelineRenderPassType::BeginRendering(rendering_info) => {
290                         rendering_info.color_attachment_formats.len()
291                     }
292                 };
293             let element = self.color_blend_state.attachments.pop().unwrap();
294             self.color_blend_state
295                 .attachments
296                 .extend(std::iter::repeat(element).take(color_attachment_count));
297         }
298 
299         let has = {
300             let Self {
301                 render_pass,
302                 cache: _,
303 
304                 vertex_shader,
305                 tessellation_shaders,
306                 geometry_shader: _,
307                 fragment_shader: _,
308 
309                 vertex_input_state: _,
310                 input_assembly_state: _,
311                 tessellation_state: _,
312                 viewport_state: _,
313                 discard_rectangle_state: _,
314                 rasterization_state,
315                 multisample_state: _,
316                 depth_stencil_state: _,
317                 color_blend_state: _,
318             } = &self;
319 
320             let render_pass = render_pass.as_ref().expect("Missing render pass");
321 
322             let has_pre_rasterization_shader_state = true;
323             let has_vertex_input_state = vertex_shader.is_some();
324             let has_fragment_shader_state =
325                 rasterization_state.rasterizer_discard_enable != StateMode::Fixed(true);
326             let has_fragment_output_state =
327                 rasterization_state.rasterizer_discard_enable != StateMode::Fixed(true);
328 
329             let has_tessellation_state =
330                 has_pre_rasterization_shader_state && tessellation_shaders.is_some();
331             let has_viewport_state =
332                 has_pre_rasterization_shader_state && has_fragment_shader_state;
333             let has_depth_stencil_state = has_fragment_shader_state
334                 && match render_pass {
335                     PipelineRenderPassType::BeginRenderPass(subpass) => {
336                         subpass.subpass_desc().depth_stencil_attachment.is_some()
337                     }
338                     PipelineRenderPassType::BeginRendering(rendering_info) => {
339                         !has_fragment_output_state
340                             || rendering_info.depth_attachment_format.is_some()
341                             || rendering_info.stencil_attachment_format.is_some()
342                     }
343                 };
344             let has_color_blend_state = has_fragment_output_state
345                 && match render_pass {
346                     PipelineRenderPassType::BeginRenderPass(subpass) => {
347                         !subpass.subpass_desc().color_attachments.is_empty()
348                     }
349                     PipelineRenderPassType::BeginRendering(rendering_info) => {
350                         !rendering_info.color_attachment_formats.is_empty()
351                     }
352                 };
353 
354             Has {
355                 vertex_input_state: has_vertex_input_state,
356                 pre_rasterization_shader_state: has_pre_rasterization_shader_state,
357                 tessellation_state: has_tessellation_state,
358                 viewport_state: has_viewport_state,
359                 fragment_shader_state: has_fragment_shader_state,
360                 depth_stencil_state: has_depth_stencil_state,
361                 fragment_output_state: has_fragment_output_state,
362                 color_blend_state: has_color_blend_state,
363             }
364         };
365 
366         self.validate_create(&device, &pipeline_layout, &vertex_input_state, has)?;
367 
368         let (handle, descriptor_requirements, dynamic_state, shaders, fragment_tests_stages) =
369             unsafe { self.record_create(&device, &pipeline_layout, &vertex_input_state, has)? };
370 
371         let Self {
372             mut render_pass,
373             cache: _,
374 
375             vertex_shader: _,
376             tessellation_shaders: _,
377             geometry_shader: _,
378             fragment_shader: _,
379 
380             vertex_input_state: _,
381             input_assembly_state,
382             tessellation_state,
383             viewport_state,
384             discard_rectangle_state,
385             rasterization_state,
386             multisample_state,
387             depth_stencil_state,
388             color_blend_state,
389         } = self;
390 
391         let num_used_descriptor_sets = descriptor_requirements
392             .keys()
393             .map(|loc| loc.0)
394             .max()
395             .map(|x| x + 1)
396             .unwrap_or(0);
397 
398         Ok(Arc::new(GraphicsPipeline {
399             handle,
400             device,
401             id: GraphicsPipeline::next_id(),
402             layout: pipeline_layout,
403             render_pass: render_pass.take().expect("Missing render pass"),
404 
405             shaders,
406             descriptor_binding_requirements: descriptor_requirements,
407             num_used_descriptor_sets,
408             fragment_tests_stages,
409 
410             vertex_input_state, // Can be None if there's a mesh shader, but we don't support that yet
411             input_assembly_state, // Can be None if there's a mesh shader, but we don't support that yet
412             tessellation_state: has.tessellation_state.then_some(tessellation_state),
413             viewport_state: has.viewport_state.then_some(viewport_state),
414             discard_rectangle_state: has
415                 .pre_rasterization_shader_state
416                 .then_some(discard_rectangle_state),
417             rasterization_state,
418             multisample_state: has.fragment_output_state.then_some(multisample_state),
419             depth_stencil_state: has.depth_stencil_state.then_some(depth_stencil_state),
420             color_blend_state: has.color_blend_state.then_some(color_blend_state),
421             dynamic_state,
422         }))
423     }
424 
validate_create( &self, device: &Device, pipeline_layout: &PipelineLayout, vertex_input_state: &VertexInputState, has: Has, ) -> Result<(), GraphicsPipelineCreationError>425     fn validate_create(
426         &self,
427         device: &Device,
428         pipeline_layout: &PipelineLayout,
429         vertex_input_state: &VertexInputState,
430         has: Has,
431     ) -> Result<(), GraphicsPipelineCreationError> {
432         let physical_device = device.physical_device();
433         let properties = physical_device.properties();
434 
435         let Self {
436             render_pass,
437             cache: _,
438 
439             vertex_shader,
440             tessellation_shaders,
441             geometry_shader,
442             fragment_shader,
443 
444             vertex_input_state: _,
445             input_assembly_state,
446             tessellation_state,
447             viewport_state,
448             discard_rectangle_state,
449             rasterization_state,
450             multisample_state,
451             depth_stencil_state,
452             color_blend_state,
453         } = self;
454 
455         let render_pass = render_pass.as_ref().expect("Missing render pass");
456 
457         let mut shader_stages: SmallVec<[_; 5]> = SmallVec::new();
458 
459         // VUID-VkGraphicsPipelineCreateInfo-layout-01688
460         // Checked at pipeline layout creation time.
461 
462         /*
463             Render pass
464         */
465 
466         match render_pass {
467             PipelineRenderPassType::BeginRenderPass(subpass) => {
468                 // VUID-VkGraphicsPipelineCreateInfo-commonparent
469                 assert_eq!(device, subpass.render_pass().device().as_ref());
470             }
471             PipelineRenderPassType::BeginRendering(rendering_info) => {
472                 let &PipelineRenderingCreateInfo {
473                     view_mask,
474                     ref color_attachment_formats,
475                     depth_attachment_format,
476                     stencil_attachment_format,
477                     _ne: _,
478                 } = rendering_info;
479 
480                 // VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576
481                 if !device.enabled_features().dynamic_rendering {
482                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
483                         required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering`",
484                         requires_one_of: RequiresOneOf {
485                             features: &["dynamic_rendering"],
486                             ..Default::default()
487                         },
488                     });
489                 }
490 
491                 // VUID-VkGraphicsPipelineCreateInfo-multiview-06577
492                 if view_mask != 0 && !device.enabled_features().multiview {
493                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
494                         required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering` \
495                             where `view_mask` is not `0`",
496                         requires_one_of: RequiresOneOf {
497                             features: &["multiview"],
498                             ..Default::default()
499                         },
500                     });
501                 }
502 
503                 let view_count = u32::BITS - view_mask.leading_zeros();
504 
505                 // VUID-VkGraphicsPipelineCreateInfo-renderPass-06578
506                 if view_count > properties.max_multiview_view_count.unwrap_or(0) {
507                     return Err(
508                         GraphicsPipelineCreationError::MaxMultiviewViewCountExceeded {
509                             view_count,
510                             max: properties.max_multiview_view_count.unwrap_or(0),
511                         },
512                     );
513                 }
514 
515                 if has.fragment_output_state {
516                     for (attachment_index, format) in color_attachment_formats
517                         .iter()
518                         .enumerate()
519                         .flat_map(|(i, f)| f.map(|f| (i, f)))
520                     {
521                         let attachment_index = attachment_index as u32;
522 
523                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06580
524                         format.validate_device(device)?;
525 
526                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06582
527                         // Use unchecked, because all validation has been done above.
528                         if !unsafe { physical_device.format_properties_unchecked(format) }
529                             .potential_format_features()
530                             .intersects(FormatFeatures::COLOR_ATTACHMENT)
531                         {
532                             return Err(
533                                 GraphicsPipelineCreationError::ColorAttachmentFormatUsageNotSupported {
534                                     attachment_index,
535                                 },
536                             );
537                         }
538                     }
539 
540                     if let Some(format) = depth_attachment_format {
541                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06583
542                         format.validate_device(device)?;
543 
544                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06585
545                         // Use unchecked, because all validation has been done above.
546                         if !unsafe { physical_device.format_properties_unchecked(format) }
547                             .potential_format_features()
548                             .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
549                         {
550                             return Err(
551                                 GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported,
552                             );
553                         }
554 
555                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06587
556                         if !format.aspects().intersects(ImageAspects::DEPTH) {
557                             return Err(
558                                 GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported,
559                             );
560                         }
561                     }
562 
563                     if let Some(format) = stencil_attachment_format {
564                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06584
565                         format.validate_device(device)?;
566 
567                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06586
568                         // Use unchecked, because all validation has been done above.
569                         if !unsafe { physical_device.format_properties_unchecked(format) }
570                             .potential_format_features()
571                             .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
572                         {
573                             return Err(
574                                 GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported,
575                             );
576                         }
577 
578                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06588
579                         if !format.aspects().intersects(ImageAspects::STENCIL) {
580                             return Err(
581                                 GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported,
582                             );
583                         }
584                     }
585 
586                     if let (Some(depth_format), Some(stencil_format)) =
587                         (depth_attachment_format, stencil_attachment_format)
588                     {
589                         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06589
590                         if depth_format != stencil_format {
591                             return Err(
592                                 GraphicsPipelineCreationError::DepthStencilAttachmentFormatMismatch,
593                             );
594                         }
595                     }
596                 }
597             }
598         }
599 
600         /*
601             Vertex input state
602         */
603 
604         if has.vertex_input_state {
605             // Vertex input state
606             // VUID-VkGraphicsPipelineCreateInfo-pVertexInputState-04910
607             {
608                 let VertexInputState {
609                     bindings,
610                     attributes,
611                 } = vertex_input_state;
612 
613                 // VUID-VkPipelineVertexInputStateCreateInfo-vertexBindingDescriptionCount-00613
614                 if bindings.len() > properties.max_vertex_input_bindings as usize {
615                     return Err(
616                         GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
617                             max: properties.max_vertex_input_bindings,
618                             obtained: bindings.len() as u32,
619                         },
620                     );
621                 }
622 
623                 // VUID-VkPipelineVertexInputStateCreateInfo-pVertexBindingDescriptions-00616
624                 // Ensured by HashMap.
625 
626                 for (&binding, binding_desc) in bindings {
627                     let &VertexInputBindingDescription { stride, input_rate } = binding_desc;
628 
629                     // VUID-VkVertexInputBindingDescription-binding-00618
630                     if binding >= properties.max_vertex_input_bindings {
631                         return Err(
632                             GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
633                                 max: properties.max_vertex_input_bindings,
634                                 obtained: binding,
635                             },
636                         );
637                     }
638 
639                     // VUID-VkVertexInputBindingDescription-stride-00619
640                     if stride > properties.max_vertex_input_binding_stride {
641                         return Err(
642                             GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
643                                 binding,
644                                 max: properties.max_vertex_input_binding_stride,
645                                 obtained: stride,
646                             },
647                         );
648                     }
649 
650                     // VUID-VkVertexInputBindingDescription-stride-04456
651                     if device.enabled_extensions().khr_portability_subset
652                         && (stride == 0
653                             || stride
654                                 % properties
655                                     .min_vertex_input_binding_stride_alignment
656                                     .unwrap()
657                                 != 0)
658                     {
659                         return Err(GraphicsPipelineCreationError::MinVertexInputBindingStrideAlignmentExceeded {
660                             binding,
661                             max: properties.min_vertex_input_binding_stride_alignment.unwrap(),
662                             obtained: binding,
663                         });
664                     }
665 
666                     match input_rate {
667                         VertexInputRate::Instance { divisor } if divisor != 1 => {
668                             // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229
669                             if !device
670                                 .enabled_features()
671                                 .vertex_attribute_instance_rate_divisor
672                             {
673                                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
674                                     required_for: "`vertex_input_state.bindings` has an element \
675                                         where `input_rate` is `VertexInputRate::Instance`, where \
676                                         `divisor` is not `1`",
677                                     requires_one_of: RequiresOneOf {
678                                         features: &["vertex_attribute_instance_rate_divisor"],
679                                         ..Default::default()
680                                     },
681                                 });
682                             }
683 
684                             // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228
685                             if divisor == 0
686                                 && !device
687                                     .enabled_features()
688                                     .vertex_attribute_instance_rate_zero_divisor
689                             {
690                                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
691                                     required_for: "`vertex_input_state.bindings` has an element \
692                                         where `input_rate` is `VertexInputRate::Instance`, where \
693                                         `divisor` is `0`",
694                                     requires_one_of: RequiresOneOf {
695                                         features: &["vertex_attribute_instance_rate_zero_divisor"],
696                                         ..Default::default()
697                                     },
698                                 });
699                             }
700 
701                             // VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870
702                             if divisor > properties.max_vertex_attrib_divisor.unwrap() {
703                                 return Err(
704                                     GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded {
705                                         binding,
706                                         max: properties.max_vertex_attrib_divisor.unwrap(),
707                                         obtained: divisor,
708                                     },
709                                 );
710                             }
711                         }
712                         _ => (),
713                     }
714                 }
715 
716                 // VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614
717                 if attributes.len() > properties.max_vertex_input_attributes as usize {
718                     return Err(
719                         GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
720                             max: properties.max_vertex_input_attributes,
721                             obtained: attributes.len(),
722                         },
723                     );
724                 }
725 
726                 // VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-00617
727                 // Ensured by HashMap with the exception of formats exceeding a single location.
728                 // When a format exceeds a single location the location following it (e.g.
729                 // R64B64G64_SFLOAT) needs to be unassigned.
730                 let unassigned_locations = attributes
731                     .iter()
732                     .filter(|&(_, attribute_desc)| attribute_desc.format.block_size().unwrap() > 16)
733                     .map(|(location, _)| location + 1);
734                 for location in unassigned_locations {
735                     if !attributes.get(&location).is_none() {
736                         return Err(
737                             GraphicsPipelineCreationError::VertexInputAttributeInvalidAssignedLocation {
738                                 location,
739                             },
740                         );
741                     }
742                 }
743 
744                 for (&location, attribute_desc) in attributes {
745                     let &VertexInputAttributeDescription {
746                         binding,
747                         format,
748                         offset,
749                     } = attribute_desc;
750 
751                     // VUID-VkVertexInputAttributeDescription-format-parameter
752                     format.validate_device(device)?;
753 
754                     // TODO:
755                     // VUID-VkVertexInputAttributeDescription-location-00620
756 
757                     // VUID-VkPipelineVertexInputStateCreateInfo-binding-00615
758                     let binding_desc = bindings.get(&binding).ok_or(
759                         GraphicsPipelineCreationError::VertexInputAttributeInvalidBinding {
760                             location,
761                             binding,
762                         },
763                     )?;
764 
765                     // VUID-VkVertexInputAttributeDescription-offset-00622
766                     if offset > properties.max_vertex_input_attribute_offset {
767                         return Err(
768                             GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
769                                 max: properties.max_vertex_input_attribute_offset,
770                                 obtained: offset,
771                             },
772                         );
773                     }
774 
775                     // Use unchecked, because all validation has been done above.
776                     let format_features = unsafe {
777                         device
778                             .physical_device()
779                             .format_properties_unchecked(format)
780                             .buffer_features
781                     };
782 
783                     // VUID-VkVertexInputAttributeDescription-format-00623
784                     if !format_features.intersects(FormatFeatures::VERTEX_BUFFER) {
785                         return Err(
786                             GraphicsPipelineCreationError::VertexInputAttributeUnsupportedFormat {
787                                 location,
788                                 format,
789                             },
790                         );
791                     }
792 
793                     // VUID-VkVertexInputAttributeDescription-vertexAttributeAccessBeyondStride-04457
794                     if device.enabled_extensions().khr_portability_subset
795                         && !device
796                             .enabled_features()
797                             .vertex_attribute_access_beyond_stride
798                         && offset as DeviceSize + format.block_size().unwrap()
799                             > binding_desc.stride as DeviceSize
800                     {
801                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
802                             required_for: "this device is a portability subset device, and \
803                                 `vertex_input_state.attributes` has an element where \
804                                 `offset + format.block_size()` is greater than the `stride` of \
805                                 `binding`",
806                             requires_one_of: RequiresOneOf {
807                                 features: &["vertex_attribute_access_beyond_stride"],
808                                 ..Default::default()
809                             },
810                         });
811                     }
812                 }
813             }
814 
815             // Input assembly state
816             // VUID-VkGraphicsPipelineCreateInfo-pStages-02098
817             {
818                 let &InputAssemblyState {
819                     topology,
820                     primitive_restart_enable,
821                 } = input_assembly_state;
822 
823                 match topology {
824                     PartialStateMode::Fixed(topology) => {
825                         // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
826                         topology.validate_device(device)?;
827 
828                         match topology {
829                             PrimitiveTopology::TriangleFan => {
830                                 // VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452
831                                 if device.enabled_extensions().khr_portability_subset
832                                     && !device.enabled_features().triangle_fans
833                                 {
834                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
835                                         required_for: "this device is a portability subset \
836                                             device, and `input_assembly_state.topology` is \
837                                             `StateMode::Fixed(PrimitiveTopology::TriangleFan)`",
838                                         requires_one_of: RequiresOneOf {
839                                             features: &["triangle_fans"],
840                                             ..Default::default()
841                                         },
842                                     });
843                                 }
844                             }
845                             PrimitiveTopology::LineListWithAdjacency
846                             | PrimitiveTopology::LineStripWithAdjacency
847                             | PrimitiveTopology::TriangleListWithAdjacency
848                             | PrimitiveTopology::TriangleStripWithAdjacency => {
849                                 // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429
850                                 if !device.enabled_features().geometry_shader {
851                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
852                                         required_for: "`input_assembly_state.topology` is \
853                                             `StateMode::Fixed(PrimitiveTopology::*WithAdjacency)`",
854                                         requires_one_of: RequiresOneOf {
855                                             features: &["geometry_shader"],
856                                             ..Default::default()
857                                         },
858                                     });
859                                 }
860                             }
861                             PrimitiveTopology::PatchList => {
862                                 // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430
863                                 if !device.enabled_features().tessellation_shader {
864                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
865                                         required_for: "`input_assembly_state.topology` is \
866                                             `StateMode::Fixed(PrimitiveTopology::PatchList)`",
867                                         requires_one_of: RequiresOneOf {
868                                             features: &["tessellation_shader"],
869                                             ..Default::default()
870                                         },
871                                     });
872                                 }
873 
874                                 // TODO:
875                                 // VUID-VkGraphicsPipelineCreateInfo-topology-00737
876                             }
877                             _ => (),
878                         }
879                     }
880                     PartialStateMode::Dynamic(topology_class) => {
881                         // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
882                         topology_class.example().validate_device(device)?;
883 
884                         // VUID?
885                         if !(device.api_version() >= Version::V1_3
886                             || device.enabled_features().extended_dynamic_state)
887                         {
888                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
889                                 required_for: "`input_assembly_state.topology` is \
890                                     `PartialStateMode::Dynamic`",
891                                 requires_one_of: RequiresOneOf {
892                                     api_version: Some(Version::V1_3),
893                                     features: &["extended_dynamic_state"],
894                                     ..Default::default()
895                                 },
896                             });
897                         }
898                     }
899                 }
900 
901                 match primitive_restart_enable {
902                     StateMode::Fixed(primitive_restart_enable) => {
903                         if primitive_restart_enable {
904                             match topology {
905                                 PartialStateMode::Fixed(
906                                     PrimitiveTopology::PointList
907                                     | PrimitiveTopology::LineList
908                                     | PrimitiveTopology::TriangleList
909                                     | PrimitiveTopology::LineListWithAdjacency
910                                     | PrimitiveTopology::TriangleListWithAdjacency,
911                                 ) => {
912                                     // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06252
913                                     if !device.enabled_features().primitive_topology_list_restart {
914                                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
915                                             required_for: "`input_assembly_state.primitive_restart_enable` \
916                                                 is `StateMode::Fixed(true)` and \
917                                                 `input_assembly_state.topology` is \
918                                                 `StateMode::Fixed(PrimitiveTopology::*List)`",
919                                             requires_one_of: RequiresOneOf {
920                                                 features: &["primitive_topology_list_restart"],
921                                                 ..Default::default()
922                                             },
923                                         });
924                                     }
925                                 }
926                                 PartialStateMode::Fixed(PrimitiveTopology::PatchList) => {
927                                     // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06253
928                                     if !device
929                                         .enabled_features()
930                                         .primitive_topology_patch_list_restart
931                                     {
932                                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
933                                             required_for: "`input_assembly_state.primitive_restart_enable` \
934                                                 is `StateMode::Fixed(true)` and \
935                                                 `input_assembly_state.topology` is \
936                                                 `StateMode::Fixed(PrimitiveTopology::PatchList)`",
937                                             requires_one_of: RequiresOneOf {
938                                                 features: &["primitive_topology_patch_list_restart"],
939                                                 ..Default::default()
940                                             },
941                                         });
942                                     }
943                                 }
944                                 _ => (),
945                             }
946                         }
947                     }
948                     StateMode::Dynamic => {
949                         // VUID?
950                         if !(device.api_version() >= Version::V1_3
951                             || device.enabled_features().extended_dynamic_state2)
952                         {
953                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
954                                 required_for: "`input_assembly_state.primitive_restart_enable` is \
955                                     `StateMode::Dynamic`",
956                                 requires_one_of: RequiresOneOf {
957                                     api_version: Some(Version::V1_3),
958                                     features: &["extended_dynamic_state2"],
959                                     ..Default::default()
960                                 },
961                             });
962                         }
963                     }
964                 };
965             }
966         }
967 
968         /*
969             Pre-rasterization shader state
970         */
971 
972         if has.pre_rasterization_shader_state {
973             // Vertex shader
974             if let Some((entry_point, specialization_data)) = vertex_shader {
975                 shader_stages.push(ShaderStageInfo {
976                     entry_point,
977                     specialization_map_entries: Vss::descriptors(),
978                     _specialization_data: unsafe {
979                         std::slice::from_raw_parts(
980                             specialization_data as *const _ as *const u8,
981                             size_of_val(specialization_data),
982                         )
983                     },
984                 });
985 
986                 match entry_point.execution() {
987                     ShaderExecution::Vertex => (),
988                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
989                 }
990 
991                 // VUID?
992                 // Check that the vertex input state contains attributes for all the shader's input
993                 // variables.
994                 for element in entry_point.input_interface().elements() {
995                     assert!(!element.ty.is_64bit); // TODO: implement
996                     let location_range =
997                         element.location..element.location + element.ty.num_locations();
998 
999                     for location in location_range {
1000                         let attribute_desc =
1001                             match vertex_input_state.attributes.get(&location) {
1002                                 Some(attribute_desc) => attribute_desc,
1003                                 None => return Err(
1004                                     GraphicsPipelineCreationError::VertexInputAttributeMissing {
1005                                         location,
1006                                     },
1007                                 ),
1008                             };
1009 
1010                         // TODO: Check component assignments too. Multiple variables can occupy the same
1011                         // location but in different components.
1012 
1013                         let shader_type = element.ty.base_type;
1014                         let attribute_type = attribute_desc.format.type_color().unwrap();
1015 
1016                         if !matches!(
1017                             (shader_type, attribute_type),
1018                             (
1019                                 ShaderScalarType::Float,
1020                                 NumericType::SFLOAT
1021                                     | NumericType::UFLOAT
1022                                     | NumericType::SNORM
1023                                     | NumericType::UNORM
1024                                     | NumericType::SSCALED
1025                                     | NumericType::USCALED
1026                                     | NumericType::SRGB,
1027                             ) | (ShaderScalarType::Sint, NumericType::SINT)
1028                                 | (ShaderScalarType::Uint, NumericType::UINT)
1029                         ) {
1030                             return Err(
1031                                 GraphicsPipelineCreationError::VertexInputAttributeIncompatibleFormat {
1032                                     location,
1033                                     shader_type,
1034                                     attribute_type,
1035                                 },
1036                             );
1037                         }
1038                     }
1039                 }
1040 
1041                 // TODO:
1042                 // VUID-VkPipelineShaderStageCreateInfo-stage-00712
1043             } else {
1044                 // VUID-VkGraphicsPipelineCreateInfo-stage-02096
1045                 panic!("Missing vertex shader"); // TODO: return error
1046             }
1047 
1048             // Tessellation shaders & tessellation state
1049             if let Some(tessellation_shaders) = tessellation_shaders {
1050                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00729
1051                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00730
1052                 // Ensured by the definition of TessellationShaders.
1053 
1054                 // FIXME: must check that the control shader and evaluation shader are compatible
1055 
1056                 // VUID-VkPipelineShaderStageCreateInfo-stage-00705
1057                 if !device.enabled_features().tessellation_shader {
1058                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1059                         required_for: "`tessellation_shaders` are provided",
1060                         requires_one_of: RequiresOneOf {
1061                             features: &["tessellation_shader"],
1062                             ..Default::default()
1063                         },
1064                     });
1065                 }
1066 
1067                 {
1068                     let (entry_point, specialization_data) = &tessellation_shaders.control;
1069 
1070                     shader_stages.push(ShaderStageInfo {
1071                         entry_point,
1072                         specialization_map_entries: Tcss::descriptors(),
1073                         _specialization_data: unsafe {
1074                             std::slice::from_raw_parts(
1075                                 specialization_data as *const _ as *const u8,
1076                                 size_of_val(specialization_data),
1077                             )
1078                         },
1079                     });
1080 
1081                     match entry_point.execution() {
1082                         ShaderExecution::TessellationControl => (),
1083                         _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
1084                     }
1085                 }
1086 
1087                 {
1088                     let (entry_point, specialization_data) = &tessellation_shaders.evaluation;
1089 
1090                     shader_stages.push(ShaderStageInfo {
1091                         entry_point,
1092                         specialization_map_entries: Tess::descriptors(),
1093                         _specialization_data: unsafe {
1094                             std::slice::from_raw_parts(
1095                                 specialization_data as *const _ as *const u8,
1096                                 size_of_val(specialization_data),
1097                             )
1098                         },
1099                     });
1100 
1101                     match entry_point.execution() {
1102                         ShaderExecution::TessellationEvaluation => (),
1103                         _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
1104                     }
1105                 }
1106 
1107                 if !device.enabled_features().multiview_tessellation_shader {
1108                     let view_mask = match render_pass {
1109                         PipelineRenderPassType::BeginRenderPass(subpass) => {
1110                             subpass.render_pass().views_used()
1111                         }
1112                         PipelineRenderPassType::BeginRendering(rendering_info) => {
1113                             rendering_info.view_mask
1114                         }
1115                     };
1116 
1117                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06047
1118                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06057
1119                     if view_mask != 0 {
1120                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1121                             required_for: "`tessellation_shaders` are provided and `render_pass` \
1122                                 has a subpass where `view_mask` is not `0`",
1123                             requires_one_of: RequiresOneOf {
1124                                 features: &["multiview_tessellation_shader"],
1125                                 ..Default::default()
1126                             },
1127                         });
1128                     }
1129                 }
1130 
1131                 // TODO:
1132                 // VUID-VkPipelineShaderStageCreateInfo-stage-00713
1133                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00732
1134                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00733
1135                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00734
1136                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00735
1137             }
1138 
1139             // Geometry shader
1140             if let Some((entry_point, specialization_data)) = geometry_shader {
1141                 shader_stages.push(ShaderStageInfo {
1142                     entry_point,
1143                     specialization_map_entries: Gss::descriptors(),
1144                     _specialization_data: unsafe {
1145                         std::slice::from_raw_parts(
1146                             specialization_data as *const _ as *const u8,
1147                             size_of_val(specialization_data),
1148                         )
1149                     },
1150                 });
1151 
1152                 // VUID-VkPipelineShaderStageCreateInfo-stage-00704
1153                 if !device.enabled_features().geometry_shader {
1154                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1155                         required_for: "`geometry_shader` is provided",
1156                         requires_one_of: RequiresOneOf {
1157                             features: &["geometry_shader"],
1158                             ..Default::default()
1159                         },
1160                     });
1161                 }
1162 
1163                 let input = match entry_point.execution() {
1164                     ShaderExecution::Geometry(execution) => execution.input,
1165                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
1166                 };
1167 
1168                 if let PartialStateMode::Fixed(topology) = input_assembly_state.topology {
1169                     // VUID-VkGraphicsPipelineCreateInfo-pStages-00738
1170                     if !input.is_compatible_with(topology) {
1171                         return Err(
1172                             GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader,
1173                         );
1174                     }
1175                 }
1176 
1177                 if !device.enabled_features().multiview_geometry_shader {
1178                     let view_mask = match render_pass {
1179                         PipelineRenderPassType::BeginRenderPass(subpass) => {
1180                             subpass.render_pass().views_used()
1181                         }
1182                         PipelineRenderPassType::BeginRendering(rendering_info) => {
1183                             rendering_info.view_mask
1184                         }
1185                     };
1186 
1187                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06048
1188                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06058
1189                     if view_mask != 0 {
1190                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1191                             required_for: "`geometry_shader` is provided and `render_pass` has a \
1192                                 subpass where `view_mask` is not `0`",
1193                             requires_one_of: RequiresOneOf {
1194                                 features: &["multiview_geometry_shader"],
1195                                 ..Default::default()
1196                             },
1197                         });
1198                     }
1199                 }
1200 
1201                 // TODO:
1202                 // VUID-VkPipelineShaderStageCreateInfo-stage-00714
1203                 // VUID-VkPipelineShaderStageCreateInfo-stage-00715
1204                 // VUID-VkGraphicsPipelineCreateInfo-pStages-00739
1205             }
1206 
1207             // Rasterization state
1208             // VUID?
1209             {
1210                 let &RasterizationState {
1211                     depth_clamp_enable,
1212                     rasterizer_discard_enable,
1213                     polygon_mode,
1214                     cull_mode,
1215                     front_face,
1216                     depth_bias,
1217                     line_width,
1218                     line_rasterization_mode,
1219                     line_stipple,
1220                 } = rasterization_state;
1221 
1222                 // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-parameter
1223                 polygon_mode.validate_device(device)?;
1224 
1225                 // VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782
1226                 if depth_clamp_enable && !device.enabled_features().depth_clamp {
1227                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1228                         required_for: "`rasterization_state.depth_clamp_enable` is set",
1229                         requires_one_of: RequiresOneOf {
1230                             features: &["depth_clamp"],
1231                             ..Default::default()
1232                         },
1233                     });
1234                 }
1235 
1236                 match rasterizer_discard_enable {
1237                     StateMode::Dynamic => {
1238                         // VUID?
1239                         if !(device.api_version() >= Version::V1_3
1240                             || device.enabled_features().extended_dynamic_state2)
1241                         {
1242                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1243                                 required_for: "`rasterization_state.rasterizer_discard_enable` is \
1244                                     `StateMode::Dynamic`",
1245                                 requires_one_of: RequiresOneOf {
1246                                     api_version: Some(Version::V1_3),
1247                                     features: &["extended_dynamic_state"],
1248                                     ..Default::default()
1249                                 },
1250                             });
1251                         }
1252                     }
1253                     StateMode::Fixed(false) => {
1254                         // VUID-VkPipelineRasterizationStateCreateInfo-pointPolygons-04458
1255                         if device.enabled_extensions().khr_portability_subset
1256                             && !device.enabled_features().point_polygons
1257                             && polygon_mode == PolygonMode::Point
1258                         {
1259                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1260                                 required_for: "this device is a portability subset device, \
1261                                     `rasterization_state.rasterizer_discard_enable` is \
1262                                     `StateMode::Fixed(false)` and \
1263                                     `rasterization_state.polygon_mode` is `PolygonMode::Point`",
1264                                 requires_one_of: RequiresOneOf {
1265                                     features: &["point_polygons"],
1266                                     ..Default::default()
1267                                 },
1268                             });
1269                         }
1270                     }
1271                     _ => (),
1272                 }
1273 
1274                 // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507
1275                 if polygon_mode != PolygonMode::Fill
1276                     && !device.enabled_features().fill_mode_non_solid
1277                 {
1278                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1279                         required_for: "`rasterization_state.polygon_mode` is not \
1280                             `PolygonMode::Fill`",
1281                         requires_one_of: RequiresOneOf {
1282                             features: &["fill_mode_non_solid"],
1283                             ..Default::default()
1284                         },
1285                     });
1286                 }
1287 
1288                 match cull_mode {
1289                     StateMode::Fixed(cull_mode) => {
1290                         // VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter
1291                         cull_mode.validate_device(device)?;
1292                     }
1293                     StateMode::Dynamic => {
1294                         // VUID?
1295                         if !(device.api_version() >= Version::V1_3
1296                             || device.enabled_features().extended_dynamic_state)
1297                         {
1298                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1299                                 required_for: "`rasterization_state.cull_mode` is \
1300                                     `StateMode::Dynamic`",
1301                                 requires_one_of: RequiresOneOf {
1302                                     api_version: Some(Version::V1_3),
1303                                     features: &["extended_dynamic_state"],
1304                                     ..Default::default()
1305                                 },
1306                             });
1307                         }
1308                     }
1309                 }
1310 
1311                 match front_face {
1312                     StateMode::Fixed(front_face) => {
1313                         // VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter
1314                         front_face.validate_device(device)?;
1315                     }
1316                     StateMode::Dynamic => {
1317                         // VUID?
1318                         if !(device.api_version() >= Version::V1_3
1319                             || device.enabled_features().extended_dynamic_state)
1320                         {
1321                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1322                                 required_for: "`rasterization_state.front_face` is \
1323                                     `StateMode::Dynamic`",
1324                                 requires_one_of: RequiresOneOf {
1325                                     api_version: Some(Version::V1_3),
1326                                     features: &["extended_dynamic_state"],
1327                                     ..Default::default()
1328                                 },
1329                             });
1330                         }
1331                     }
1332                 }
1333 
1334                 if let Some(depth_bias_state) = depth_bias {
1335                     let DepthBiasState {
1336                         enable_dynamic,
1337                         bias,
1338                     } = depth_bias_state;
1339 
1340                     // VUID?
1341                     if enable_dynamic
1342                         && !(device.api_version() >= Version::V1_3
1343                             || device.enabled_features().extended_dynamic_state2)
1344                     {
1345                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1346                             required_for: "`rasterization_state.depth_bias` is \
1347                                 `Some(depth_bias_state)`, where `depth_bias_state.enable_dynamic` \
1348                                 is set",
1349                             requires_one_of: RequiresOneOf {
1350                                 api_version: Some(Version::V1_3),
1351                                 features: &["extended_dynamic_state2"],
1352                                 ..Default::default()
1353                             },
1354                         });
1355                     }
1356 
1357                     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754
1358                     if matches!(bias, StateMode::Fixed(bias) if bias.clamp != 0.0)
1359                         && !device.enabled_features().depth_bias_clamp
1360                     {
1361                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1362                             required_for: "`rasterization_state.depth_bias` is \
1363                             `Some(depth_bias_state)`, where `depth_bias_state.bias` is \
1364                             `StateMode::Fixed(bias)`, where `bias.clamp` is not `0.0`",
1365                             requires_one_of: RequiresOneOf {
1366                                 features: &["depth_bias_clamp"],
1367                                 ..Default::default()
1368                             },
1369                         });
1370                     }
1371                 }
1372 
1373                 // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749
1374                 if matches!(line_width, StateMode::Fixed(line_width) if line_width != 1.0)
1375                     && !device.enabled_features().wide_lines
1376                 {
1377                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1378                         required_for: "`rasterization_state.line_width` is \
1379                             `StateMode::Fixed(line_width)`, where `line_width` is not `1.0`",
1380                         requires_one_of: RequiresOneOf {
1381                             features: &["wide_lines"],
1382                             ..Default::default()
1383                         },
1384                     });
1385                 }
1386 
1387                 if device.enabled_extensions().ext_line_rasterization {
1388                     // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-parameter
1389                     line_rasterization_mode.validate_device(device)?;
1390 
1391                     match line_rasterization_mode {
1392                         LineRasterizationMode::Default => (),
1393                         LineRasterizationMode::Rectangular => {
1394                             // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02768
1395                             if !device.enabled_features().rectangular_lines {
1396                                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
1397                                     required_for: "`rasterization_state.line_rasterization_mode` \
1398                                         is `LineRasterizationMode::Rectangular`",
1399                                     requires_one_of: RequiresOneOf {
1400                                         features: &["rectangular_lines"],
1401                                         ..Default::default()
1402                                     },
1403                                 });
1404                             }
1405                         }
1406                         LineRasterizationMode::Bresenham => {
1407                             // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769
1408                             if !device.enabled_features().bresenham_lines {
1409                                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
1410                                     required_for: "`rasterization_state.line_rasterization_mode` \
1411                                         is `LineRasterizationMode::Bresenham`",
1412                                     requires_one_of: RequiresOneOf {
1413                                         features: &["bresenham_lines"],
1414                                         ..Default::default()
1415                                     },
1416                                 });
1417                             }
1418                         }
1419                         LineRasterizationMode::RectangularSmooth => {
1420                             // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02770
1421                             if !device.enabled_features().smooth_lines {
1422                                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
1423                                     required_for: "`rasterization_state.line_rasterization_mode` \
1424                                         is `LineRasterizationMode::RectangularSmooth`",
1425                                     requires_one_of: RequiresOneOf {
1426                                         features: &["smooth_lines"],
1427                                         ..Default::default()
1428                                     },
1429                                 });
1430                             }
1431                         }
1432                     }
1433 
1434                     if let Some(line_stipple) = line_stipple {
1435                         match line_rasterization_mode {
1436                             LineRasterizationMode::Default => {
1437                                 // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774
1438                                 if !device.enabled_features().stippled_rectangular_lines {
1439                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1440                                         required_for: "`rasterization_state.line_stipple` is \
1441                                             `Some` and \
1442                                             `rasterization_state.line_rasterization_mode` \
1443                                             is `LineRasterizationMode::Default`",
1444                                         requires_one_of: RequiresOneOf {
1445                                             features: &["stippled_rectangular_lines"],
1446                                             ..Default::default()
1447                                         },
1448                                     });
1449                                 }
1450 
1451                                 // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774
1452                                 if !properties.strict_lines {
1453                                     return Err(
1454                                         GraphicsPipelineCreationError::StrictLinesNotSupported,
1455                                     );
1456                                 }
1457                             }
1458                             LineRasterizationMode::Rectangular => {
1459                                 // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02771
1460                                 if !device.enabled_features().stippled_rectangular_lines {
1461                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1462                                         required_for: "`rasterization_state.line_stipple` is \
1463                                             `Some` and \
1464                                             `rasterization_state.line_rasterization_mode` \
1465                                             is `LineRasterizationMode::Rectangular`",
1466                                         requires_one_of: RequiresOneOf {
1467                                             features: &["stippled_rectangular_lines"],
1468                                             ..Default::default()
1469                                         },
1470                                     });
1471                                 }
1472                             }
1473                             LineRasterizationMode::Bresenham => {
1474                                 // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02772
1475                                 if !device.enabled_features().stippled_bresenham_lines {
1476                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1477                                         required_for: "`rasterization_state.line_stipple` is \
1478                                             `Some` and \
1479                                             `rasterization_state.line_rasterization_mode` \
1480                                             is `LineRasterizationMode::Bresenham`",
1481                                         requires_one_of: RequiresOneOf {
1482                                             features: &["stippled_bresenham_lines"],
1483                                             ..Default::default()
1484                                         },
1485                                     });
1486                                 }
1487                             }
1488                             LineRasterizationMode::RectangularSmooth => {
1489                                 // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02773
1490                                 if !device.enabled_features().stippled_smooth_lines {
1491                                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1492                                         required_for: "`rasterization_state.line_stipple` is \
1493                                             `Some` and \
1494                                             `rasterization_state.line_rasterization_mode` \
1495                                             is `LineRasterizationMode::RectangularSmooth`",
1496                                         requires_one_of: RequiresOneOf {
1497                                             features: &["stippled_smooth_lines"],
1498                                             ..Default::default()
1499                                         },
1500                                     });
1501                                 }
1502                             }
1503                         }
1504 
1505                         if let StateMode::Fixed(line_stipple) = line_stipple {
1506                             // VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767
1507                             assert!(line_stipple.factor >= 1 && line_stipple.factor <= 256);
1508                             // TODO: return error?
1509                         }
1510                     }
1511                 } else {
1512                     if line_rasterization_mode != LineRasterizationMode::Default {
1513                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1514                             required_for: "`rasterization_state.line_rasterization_mode` is not \
1515                                 `LineRasterizationMode::Default`",
1516                             requires_one_of: RequiresOneOf {
1517                                 device_extensions: &["ext_line_rasterization"],
1518                                 ..Default::default()
1519                             },
1520                         });
1521                     }
1522 
1523                     if line_stipple.is_some() {
1524                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1525                             required_for: "`rasterization_state.line_stipple` is `Some`",
1526                             requires_one_of: RequiresOneOf {
1527                                 device_extensions: &["ext_line_rasterization"],
1528                                 ..Default::default()
1529                             },
1530                         });
1531                     }
1532                 }
1533             }
1534 
1535             // Discard rectangle state
1536             {
1537                 let DiscardRectangleState { mode, rectangles } = discard_rectangle_state;
1538 
1539                 if device.enabled_extensions().ext_discard_rectangles {
1540                     // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleMode-parameter
1541                     mode.validate_device(device)?;
1542 
1543                     let discard_rectangle_count = match rectangles {
1544                         PartialStateMode::Dynamic(count) => *count,
1545                         PartialStateMode::Fixed(rectangles) => rectangles.len() as u32,
1546                     };
1547 
1548                     // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582
1549                     if discard_rectangle_count > properties.max_discard_rectangles.unwrap() {
1550                         return Err(
1551                             GraphicsPipelineCreationError::MaxDiscardRectanglesExceeded {
1552                                 max: properties.max_discard_rectangles.unwrap(),
1553                                 obtained: discard_rectangle_count,
1554                             },
1555                         );
1556                     }
1557                 } else {
1558                     let error = match rectangles {
1559                         PartialStateMode::Dynamic(_) => true,
1560                         PartialStateMode::Fixed(rectangles) => !rectangles.is_empty(),
1561                     };
1562 
1563                     if error {
1564                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1565                             required_for: "`discard_rectangle_state.rectangles` is not \
1566                                 `PartialStateMode::Fixed(vec![])`",
1567                             requires_one_of: RequiresOneOf {
1568                                 device_extensions: &["ext_discard_rectangles"],
1569                                 ..Default::default()
1570                             },
1571                         });
1572                     }
1573                 }
1574             }
1575 
1576             // TODO:
1577             // VUID-VkPipelineShaderStageCreateInfo-stage-02596
1578             // VUID-VkPipelineShaderStageCreateInfo-stage-02597
1579             // VUID-VkGraphicsPipelineCreateInfo-pStages-00740
1580             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06049
1581             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06050
1582             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06059
1583         }
1584 
1585         // VUID-VkGraphicsPipelineCreateInfo-pStages-00731
1586         if has.tessellation_state {
1587             let &TessellationState {
1588                 patch_control_points,
1589             } = tessellation_state;
1590 
1591             // VUID-VkGraphicsPipelineCreateInfo-pStages-00736
1592             if !matches!(
1593                 input_assembly_state.topology,
1594                 PartialStateMode::Dynamic(PrimitiveTopologyClass::Patch)
1595                     | PartialStateMode::Fixed(PrimitiveTopology::PatchList)
1596             ) {
1597                 return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
1598             }
1599 
1600             match patch_control_points {
1601                 StateMode::Fixed(patch_control_points) => {
1602                     // VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214
1603                     if patch_control_points == 0
1604                         || patch_control_points > properties.max_tessellation_patch_size
1605                     {
1606                         return Err(GraphicsPipelineCreationError::InvalidNumPatchControlPoints);
1607                     }
1608                 }
1609                 StateMode::Dynamic => {
1610                     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870
1611                     if !device
1612                         .enabled_features()
1613                         .extended_dynamic_state2_patch_control_points
1614                     {
1615                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
1616                             required_for: "`tessellation_state.patch_control_points` is \
1617                                 `StateMode::Dynamic`",
1618                             requires_one_of: RequiresOneOf {
1619                                 features: &["extended_dynamic_state2_patch_control_points"],
1620                                 ..Default::default()
1621                             },
1622                         });
1623                     }
1624                 }
1625             };
1626         }
1627 
1628         // Viewport state
1629         // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00750
1630         // VUID-VkGraphicsPipelineCreateInfo-pViewportState-04892
1631         if has.viewport_state {
1632             let (viewport_count, scissor_count) = match viewport_state {
1633                 ViewportState::Fixed { data } => {
1634                     let count = data.len() as u32;
1635                     assert!(count != 0); // TODO: return error?
1636 
1637                     for (viewport, _) in data {
1638                         for i in 0..2 {
1639                             if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32
1640                             {
1641                                 return Err(
1642                                     GraphicsPipelineCreationError::MaxViewportDimensionsExceeded,
1643                                 );
1644                             }
1645 
1646                             if viewport.origin[i] < properties.viewport_bounds_range[0]
1647                                 || viewport.origin[i] + viewport.dimensions[i]
1648                                     > properties.viewport_bounds_range[1]
1649                             {
1650                                 return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
1651                             }
1652                         }
1653                     }
1654 
1655                     // TODO:
1656                     // VUID-VkPipelineViewportStateCreateInfo-offset-02822
1657                     // VUID-VkPipelineViewportStateCreateInfo-offset-02823
1658 
1659                     (count, count)
1660                 }
1661                 ViewportState::FixedViewport {
1662                     viewports,
1663                     scissor_count_dynamic,
1664                 } => {
1665                     let viewport_count = viewports.len() as u32;
1666 
1667                     // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
1668                     assert!(viewport_count != 0); // TODO: return error?
1669 
1670                     for viewport in viewports {
1671                         for i in 0..2 {
1672                             if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32
1673                             {
1674                                 return Err(
1675                                     GraphicsPipelineCreationError::MaxViewportDimensionsExceeded,
1676                                 );
1677                             }
1678 
1679                             if viewport.origin[i] < properties.viewport_bounds_range[0]
1680                                 || viewport.origin[i] + viewport.dimensions[i]
1681                                     > properties.viewport_bounds_range[1]
1682                             {
1683                                 return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
1684                             }
1685                         }
1686                     }
1687 
1688                     // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
1689                     let scissor_count = if *scissor_count_dynamic {
1690                         if !(device.api_version() >= Version::V1_3
1691                             || device.enabled_features().extended_dynamic_state)
1692                         {
1693                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1694                                 required_for: "`viewport_state` is \
1695                                     `ViewportState::FixedViewport`, where `scissor_count_dynamic` \
1696                                     is set",
1697                                 requires_one_of: RequiresOneOf {
1698                                     api_version: Some(Version::V1_3),
1699                                     features: &["extended_dynamic_state"],
1700                                     ..Default::default()
1701                                 },
1702                             });
1703                         }
1704 
1705                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380
1706                         0
1707                     } else {
1708                         viewport_count
1709                     };
1710 
1711                     (viewport_count, scissor_count)
1712                 }
1713                 ViewportState::FixedScissor {
1714                     scissors,
1715                     viewport_count_dynamic,
1716                 } => {
1717                     let scissor_count = scissors.len() as u32;
1718 
1719                     // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
1720                     assert!(scissor_count != 0); // TODO: return error?
1721 
1722                     // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
1723                     let viewport_count = if *viewport_count_dynamic {
1724                         if !(device.api_version() >= Version::V1_3
1725                             || device.enabled_features().extended_dynamic_state)
1726                         {
1727                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1728                                 required_for: "`viewport_state` is \
1729                                     `ViewportState::FixedScissor`, where `viewport_count_dynamic` \
1730                                     is set",
1731                                 requires_one_of: RequiresOneOf {
1732                                     api_version: Some(Version::V1_3),
1733                                     features: &["extended_dynamic_state"],
1734                                     ..Default::default()
1735                                 },
1736                             });
1737                         }
1738 
1739                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379
1740                         0
1741                     } else {
1742                         scissor_count
1743                     };
1744 
1745                     // TODO:
1746                     // VUID-VkPipelineViewportStateCreateInfo-offset-02822
1747                     // VUID-VkPipelineViewportStateCreateInfo-offset-02823
1748 
1749                     (viewport_count, scissor_count)
1750                 }
1751                 &ViewportState::Dynamic {
1752                     count,
1753                     viewport_count_dynamic,
1754                     scissor_count_dynamic,
1755                 } => {
1756                     // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
1757                     // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
1758                     if !(viewport_count_dynamic && scissor_count_dynamic) {
1759                         assert!(count != 0); // TODO: return error?
1760                     }
1761 
1762                     // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
1763                     let viewport_count = if viewport_count_dynamic {
1764                         if !(device.api_version() >= Version::V1_3
1765                             || device.enabled_features().extended_dynamic_state)
1766                         {
1767                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1768                                 required_for: "`viewport_state` is \
1769                                     `ViewportState::Dynamic`, where `viewport_count_dynamic` \
1770                                     is set",
1771                                 requires_one_of: RequiresOneOf {
1772                                     api_version: Some(Version::V1_3),
1773                                     features: &["extended_dynamic_state"],
1774                                     ..Default::default()
1775                                 },
1776                             });
1777                         }
1778 
1779                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379
1780                         0
1781                     } else {
1782                         count
1783                     };
1784 
1785                     // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
1786                     let scissor_count = if scissor_count_dynamic {
1787                         if !(device.api_version() >= Version::V1_3
1788                             || device.enabled_features().extended_dynamic_state)
1789                         {
1790                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1791                                 required_for: "`viewport_state` is \
1792                                     `ViewportState::Dynamic`, where `scissor_count_dynamic` \
1793                                     is set",
1794                                 requires_one_of: RequiresOneOf {
1795                                     api_version: Some(Version::V1_3),
1796                                     features: &["extended_dynamic_state"],
1797                                     ..Default::default()
1798                                 },
1799                             });
1800                         }
1801 
1802                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380
1803                         0
1804                     } else {
1805                         count
1806                     };
1807 
1808                     (viewport_count, scissor_count)
1809                 }
1810             };
1811 
1812             // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04134
1813             // Ensured by the definition of `ViewportState`.
1814 
1815             let viewport_scissor_count = u32::max(viewport_count, scissor_count);
1816 
1817             // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216
1818             // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217
1819             if viewport_scissor_count > 1 && !device.enabled_features().multi_viewport {
1820                 return Err(GraphicsPipelineCreationError::RequirementNotMet {
1821                     required_for: "`viewport_state` has a fixed viewport/scissor count that is \
1822                         greater than `1`",
1823                     requires_one_of: RequiresOneOf {
1824                         features: &["multi_viewport"],
1825                         ..Default::default()
1826                     },
1827                 });
1828             }
1829 
1830             // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01218
1831             // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01219
1832             if viewport_scissor_count > properties.max_viewports {
1833                 return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
1834                     obtained: viewport_scissor_count,
1835                     max: properties.max_viewports,
1836                 });
1837             }
1838 
1839             // TODO:
1840             // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04503
1841             // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04504
1842         }
1843 
1844         /*
1845             Fragment shader state
1846         */
1847 
1848         if has.fragment_shader_state {
1849             // Fragment shader
1850             if let Some((entry_point, specialization_data)) = fragment_shader {
1851                 shader_stages.push(ShaderStageInfo {
1852                     entry_point,
1853                     specialization_map_entries: Fss::descriptors(),
1854                     _specialization_data: unsafe {
1855                         std::slice::from_raw_parts(
1856                             specialization_data as *const _ as *const u8,
1857                             size_of_val(specialization_data),
1858                         )
1859                     },
1860                 });
1861 
1862                 match entry_point.execution() {
1863                     ShaderExecution::Fragment(_) => (),
1864                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
1865                 }
1866 
1867                 // Check that the subpass can accept the output of the fragment shader.
1868                 match render_pass {
1869                     PipelineRenderPassType::BeginRenderPass(subpass) => {
1870                         if !subpass.is_compatible_with(entry_point.output_interface()) {
1871                             return Err(
1872                                 GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible,
1873                             );
1874                         }
1875                     }
1876                     PipelineRenderPassType::BeginRendering(_) => {
1877                         // TODO:
1878                     }
1879                 }
1880 
1881                 // TODO:
1882                 // VUID-VkPipelineShaderStageCreateInfo-stage-00718
1883                 // VUID-VkPipelineShaderStageCreateInfo-stage-06685
1884                 // VUID-VkPipelineShaderStageCreateInfo-stage-06686
1885                 // VUID-VkGraphicsPipelineCreateInfo-pStages-01565
1886                 // VUID-VkGraphicsPipelineCreateInfo-renderPass-06056
1887                 // VUID-VkGraphicsPipelineCreateInfo-renderPass-06061
1888             } else {
1889                 // TODO: should probably error out here at least under some circumstances?
1890                 // VUID?
1891             }
1892 
1893             // TODO:
1894             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06038
1895         }
1896 
1897         // Depth/stencil state
1898         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06043
1899         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06053
1900         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06590
1901         if has.depth_stencil_state {
1902             let DepthStencilState {
1903                 depth,
1904                 depth_bounds,
1905                 stencil,
1906             } = depth_stencil_state;
1907 
1908             if let Some(depth_state) = depth {
1909                 let &DepthState {
1910                     enable_dynamic,
1911                     write_enable,
1912                     compare_op,
1913                 } = depth_state;
1914 
1915                 let has_depth_attachment = match render_pass {
1916                     PipelineRenderPassType::BeginRenderPass(subpass) => subpass.has_depth(),
1917                     PipelineRenderPassType::BeginRendering(rendering_info) => {
1918                         rendering_info.depth_attachment_format.is_some()
1919                     }
1920                 };
1921 
1922                 // VUID?
1923                 if !has_depth_attachment {
1924                     return Err(GraphicsPipelineCreationError::NoDepthAttachment);
1925                 }
1926 
1927                 // VUID?
1928                 if enable_dynamic
1929                     && !(device.api_version() >= Version::V1_3
1930                         || device.enabled_features().extended_dynamic_state)
1931                 {
1932                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
1933                         required_for: "`depth_stencil_state.depth` is `Some(depth_state)`, where \
1934                              `depth_state.enable_dynamic` is set",
1935                         requires_one_of: RequiresOneOf {
1936                             api_version: Some(Version::V1_3),
1937                             features: &["extended_dynamic_state"],
1938                             ..Default::default()
1939                         },
1940                     });
1941                 }
1942 
1943                 match write_enable {
1944                     StateMode::Fixed(write_enable) => {
1945                         match render_pass {
1946                             PipelineRenderPassType::BeginRenderPass(subpass) => {
1947                                 // VUID-VkGraphicsPipelineCreateInfo-renderPass-06039
1948                                 if write_enable && !subpass.has_writable_depth() {
1949                                     return Err(GraphicsPipelineCreationError::NoDepthAttachment);
1950                                 }
1951                             }
1952                             PipelineRenderPassType::BeginRendering(_) => {
1953                                 // No VUID?
1954                             }
1955                         }
1956                     }
1957                     StateMode::Dynamic => {
1958                         // VUID?
1959                         if !(device.api_version() >= Version::V1_3
1960                             || device.enabled_features().extended_dynamic_state)
1961                         {
1962                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1963                                 required_for: "`depth_stencil_state.depth` is \
1964                                     `Some(depth_state)`, where `depth_state.write_enable` is \
1965                                     `StateMode::Dynamic`",
1966                                 requires_one_of: RequiresOneOf {
1967                                     api_version: Some(Version::V1_3),
1968                                     features: &["extended_dynamic_state"],
1969                                     ..Default::default()
1970                                 },
1971                             });
1972                         }
1973                     }
1974                 }
1975 
1976                 match compare_op {
1977                     StateMode::Fixed(compare_op) => {
1978                         // VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter
1979                         compare_op.validate_device(device)?;
1980                     }
1981                     StateMode::Dynamic => {
1982                         // VUID?
1983                         if !(device.api_version() >= Version::V1_3
1984                             || device.enabled_features().extended_dynamic_state)
1985                         {
1986                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
1987                                 required_for: "`depth_stencil_state.depth` is \
1988                                     `Some(depth_state)`, where `depth_state.compare_op` is \
1989                                         `StateMode::Dynamic`",
1990                                 requires_one_of: RequiresOneOf {
1991                                     api_version: Some(Version::V1_3),
1992                                     features: &["extended_dynamic_state"],
1993                                     ..Default::default()
1994                                 },
1995                             });
1996                         }
1997                     }
1998                 }
1999             }
2000 
2001             if let Some(depth_bounds_state) = depth_bounds {
2002                 let DepthBoundsState {
2003                     enable_dynamic,
2004                     bounds,
2005                 } = depth_bounds_state;
2006 
2007                 // VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598
2008                 if !device.enabled_features().depth_bounds {
2009                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2010                         required_for: "`depth_stencil_state.depth_bounds` is `Some`",
2011                         requires_one_of: RequiresOneOf {
2012                             features: &["depth_bounds"],
2013                             ..Default::default()
2014                         },
2015                     });
2016                 }
2017 
2018                 // VUID?
2019                 if *enable_dynamic
2020                     && !(device.api_version() >= Version::V1_3
2021                         || device.enabled_features().extended_dynamic_state)
2022                 {
2023                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2024                         required_for: "`depth_stencil_state.depth_bounds` is \
2025                             `Some(depth_bounds_state)`, where `depth_bounds_state.enable_dynamic` \
2026                             is set",
2027                         requires_one_of: RequiresOneOf {
2028                             api_version: Some(Version::V1_3),
2029                             features: &["extended_dynamic_state"],
2030                             ..Default::default()
2031                         },
2032                     });
2033                 }
2034 
2035                 if let StateMode::Fixed(bounds) = bounds {
2036                     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510
2037                     if !device.enabled_extensions().ext_depth_range_unrestricted
2038                         && !(0.0..1.0).contains(bounds.start())
2039                         && !(0.0..1.0).contains(bounds.end())
2040                     {
2041                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
2042                             required_for: "`depth_stencil_state.depth_bounds` is \
2043                                 `Some(depth_bounds_state)`, where `depth_bounds_state.bounds` is \
2044                                 not between `0.0` and `1.0` inclusive",
2045                             requires_one_of: RequiresOneOf {
2046                                 device_extensions: &["ext_depth_range_unrestricted"],
2047                                 ..Default::default()
2048                             },
2049                         });
2050                     }
2051                 }
2052             }
2053 
2054             if let Some(stencil_state) = stencil {
2055                 let StencilState {
2056                     enable_dynamic,
2057                     front,
2058                     back,
2059                 } = stencil_state;
2060 
2061                 let has_stencil_attachment = match render_pass {
2062                     PipelineRenderPassType::BeginRenderPass(subpass) => subpass.has_stencil(),
2063                     PipelineRenderPassType::BeginRendering(rendering_info) => {
2064                         rendering_info.stencil_attachment_format.is_some()
2065                     }
2066                 };
2067 
2068                 if !has_stencil_attachment {
2069                     return Err(GraphicsPipelineCreationError::NoStencilAttachment);
2070                 }
2071 
2072                 // VUID?
2073                 if *enable_dynamic
2074                     && !(device.api_version() >= Version::V1_3
2075                         || device.enabled_features().extended_dynamic_state)
2076                 {
2077                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2078                         required_for: "`depth_stencil_state.stencil` is `Some(stencil_state)`, \
2079                             where `stencil_state.enable_dynamic` is set",
2080                         requires_one_of: RequiresOneOf {
2081                             api_version: Some(Version::V1_3),
2082                             features: &["extended_dynamic_state"],
2083                             ..Default::default()
2084                         },
2085                     });
2086                 }
2087 
2088                 match (front.ops, back.ops) {
2089                     (StateMode::Fixed(front_ops), StateMode::Fixed(back_ops)) => {
2090                         for ops in [front_ops, back_ops] {
2091                             let StencilOps {
2092                                 fail_op,
2093                                 pass_op,
2094                                 depth_fail_op,
2095                                 compare_op,
2096                             } = ops;
2097 
2098                             // VUID-VkStencilOpState-failOp-parameter
2099                             fail_op.validate_device(device)?;
2100 
2101                             // VUID-VkStencilOpState-passOp-parameter
2102                             pass_op.validate_device(device)?;
2103 
2104                             // VUID-VkStencilOpState-depthFailOp-parameter
2105                             depth_fail_op.validate_device(device)?;
2106 
2107                             // VUID-VkStencilOpState-compareOp-parameter
2108                             compare_op.validate_device(device)?;
2109                         }
2110                     }
2111                     (StateMode::Dynamic, StateMode::Dynamic) => {
2112                         // VUID?
2113                         if !(device.api_version() >= Version::V1_3
2114                             || device.enabled_features().extended_dynamic_state)
2115                         {
2116                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
2117                                 required_for: "`depth_stencil_state.stencil` is \
2118                                     `Some(stencil_state)`, where `stencil_state.front.ops` and \
2119                                     `stencil_state.back.ops` are `StateMode::Dynamic`",
2120                                 requires_one_of: RequiresOneOf {
2121                                     api_version: Some(Version::V1_3),
2122                                     features: &["extended_dynamic_state"],
2123                                     ..Default::default()
2124                                 },
2125                             });
2126                         }
2127                     }
2128                     _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
2129                 }
2130 
2131                 if !matches!(
2132                     (front.compare_mask, back.compare_mask),
2133                     (StateMode::Fixed(_), StateMode::Fixed(_))
2134                         | (StateMode::Dynamic, StateMode::Dynamic)
2135                 ) {
2136                     return Err(GraphicsPipelineCreationError::WrongStencilState);
2137                 }
2138 
2139                 if !matches!(
2140                     (front.write_mask, back.write_mask),
2141                     (StateMode::Fixed(_), StateMode::Fixed(_))
2142                         | (StateMode::Dynamic, StateMode::Dynamic)
2143                 ) {
2144                     return Err(GraphicsPipelineCreationError::WrongStencilState);
2145                 }
2146 
2147                 match (front.reference, back.reference) {
2148                     (StateMode::Fixed(front_reference), StateMode::Fixed(back_reference)) => {
2149                         // VUID-VkPipelineDepthStencilStateCreateInfo-separateStencilMaskRef-04453
2150                         if device.enabled_extensions().khr_portability_subset
2151                             && !device.enabled_features().separate_stencil_mask_ref
2152                             && matches!(
2153                                 rasterization_state.cull_mode,
2154                                 StateMode::Fixed(CullMode::None)
2155                             )
2156                             && front_reference != back_reference
2157                         {
2158                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
2159                                 required_for: "this device is a portability subset device, \
2160                                     `rasterization_state.cull_mode` is \
2161                                     `StateMode::Fixed(CullMode::None)`, and \
2162                                     `depth_stencil_state.stencil` is `Some(stencil_state)`, \
2163                                     where `stencil_state.front.reference` does not equal \
2164                                     `stencil_state.back.reference`",
2165                                 requires_one_of: RequiresOneOf {
2166                                     features: &["separate_stencil_mask_ref"],
2167                                     ..Default::default()
2168                                 },
2169                             });
2170                         }
2171                     }
2172                     (StateMode::Dynamic, StateMode::Dynamic) => (),
2173                     _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
2174                 }
2175 
2176                 // TODO:
2177                 // VUID-VkGraphicsPipelineCreateInfo-renderPass-06040
2178             }
2179         }
2180 
2181         /*
2182             Fragment output state
2183         */
2184 
2185         if has.fragment_output_state {
2186             // Multisample state
2187             // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00751
2188             {
2189                 let &MultisampleState {
2190                     rasterization_samples,
2191                     sample_shading,
2192                     sample_mask: _,
2193                     alpha_to_coverage_enable: _,
2194                     alpha_to_one_enable,
2195                 } = multisample_state;
2196 
2197                 // VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter
2198                 rasterization_samples.validate_device(device)?;
2199 
2200                 match render_pass {
2201                     PipelineRenderPassType::BeginRenderPass(subpass) => {
2202                         if let Some(samples) = subpass.num_samples() {
2203                             // VUID-VkGraphicsPipelineCreateInfo-subpass-00757
2204                             if rasterization_samples != samples {
2205                                 return Err(GraphicsPipelineCreationError::MultisampleRasterizationSamplesMismatch);
2206                             }
2207                         }
2208 
2209                         // TODO:
2210                         // VUID-VkGraphicsPipelineCreateInfo-subpass-00758
2211                         // VUID-VkGraphicsPipelineCreateInfo-subpass-01505
2212                         // VUID-VkGraphicsPipelineCreateInfo-subpass-01411
2213                         // VUID-VkGraphicsPipelineCreateInfo-subpass-01412
2214                     }
2215                     PipelineRenderPassType::BeginRendering(_) => {
2216                         // No equivalent VUIDs for dynamic rendering, as no sample count information
2217                         // is provided until `begin_rendering`.
2218                     }
2219                 }
2220 
2221                 if let Some(min_sample_shading) = sample_shading {
2222                     // VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784
2223                     if !device.enabled_features().sample_rate_shading {
2224                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
2225                             required_for: "`multisample_state.sample_shading` is `Some`",
2226                             requires_one_of: RequiresOneOf {
2227                                 features: &["sample_rate_shading"],
2228                                 ..Default::default()
2229                             },
2230                         });
2231                     }
2232 
2233                     // VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786
2234                     // TODO: return error?
2235                     assert!((0.0..=1.0).contains(&min_sample_shading));
2236                 }
2237 
2238                 // VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785
2239                 if alpha_to_one_enable && !device.enabled_features().alpha_to_one {
2240                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2241                         required_for: "`multisample_state.alpha_to_one_enable` is set",
2242                         requires_one_of: RequiresOneOf {
2243                             features: &["alpha_to_one"],
2244                             ..Default::default()
2245                         },
2246                     });
2247                 }
2248 
2249                 // TODO:
2250                 // VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766
2251             }
2252         }
2253 
2254         // Color blend state
2255         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06044
2256         // VUID-VkGraphicsPipelineCreateInfo-renderPass-06054
2257         if has.color_blend_state {
2258             let ColorBlendState {
2259                 logic_op,
2260                 attachments,
2261                 blend_constants: _,
2262             } = color_blend_state;
2263 
2264             if let Some(logic_op) = logic_op {
2265                 // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606
2266                 if !device.enabled_features().logic_op {
2267                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2268                         required_for: "`color_blend_state.logic_op` is `Some`",
2269                         requires_one_of: RequiresOneOf {
2270                             features: &["logic_op"],
2271                             ..Default::default()
2272                         },
2273                     });
2274                 }
2275 
2276                 match logic_op {
2277                     StateMode::Fixed(logic_op) => {
2278                         // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607
2279                         logic_op.validate_device(device)?
2280                     }
2281                     StateMode::Dynamic => {
2282                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869
2283                         if !device.enabled_features().extended_dynamic_state2_logic_op {
2284                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
2285                                 required_for: "`color_blend_state.logic_op` is \
2286                                     `Some(StateMode::Dynamic)`",
2287                                 requires_one_of: RequiresOneOf {
2288                                     features: &["extended_dynamic_state2_logic_op"],
2289                                     ..Default::default()
2290                                 },
2291                             });
2292                         }
2293                     }
2294                 }
2295             }
2296 
2297             let color_attachment_count = match render_pass {
2298                 PipelineRenderPassType::BeginRenderPass(subpass) => {
2299                     subpass.subpass_desc().color_attachments.len()
2300                 }
2301                 PipelineRenderPassType::BeginRendering(rendering_info) => {
2302                     rendering_info.color_attachment_formats.len()
2303                 }
2304             };
2305 
2306             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06042
2307             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06055
2308             // VUID-VkGraphicsPipelineCreateInfo-renderPass-06060
2309             if color_attachment_count != attachments.len() {
2310                 return Err(GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount);
2311             }
2312 
2313             if attachments.len() > 1 && !device.enabled_features().independent_blend {
2314                 // Ensure that all `blend` and `color_write_mask` are identical.
2315                 let mut iter = attachments
2316                     .iter()
2317                     .map(|state| (&state.blend, &state.color_write_mask));
2318                 let first = iter.next().unwrap();
2319 
2320                 // VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605
2321                 if !iter.all(|state| state == first) {
2322                     return Err(GraphicsPipelineCreationError::RequirementNotMet {
2323                         required_for: "`color_blend_state.attachments` has elements where \
2324                             `blend` and `color_write_mask` do not match the other elements",
2325                         requires_one_of: RequiresOneOf {
2326                             features: &["independent_blend"],
2327                             ..Default::default()
2328                         },
2329                     });
2330                 }
2331             }
2332 
2333             for (attachment_index, state) in attachments.iter().enumerate() {
2334                 let &ColorBlendAttachmentState {
2335                     blend,
2336                     color_write_mask: _,
2337                     color_write_enable,
2338                 } = state;
2339 
2340                 if let Some(blend) = blend {
2341                     let AttachmentBlend {
2342                         color_op,
2343                         color_source,
2344                         color_destination,
2345                         alpha_op,
2346                         alpha_source,
2347                         alpha_destination,
2348                     } = blend;
2349 
2350                     // VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter
2351                     color_op.validate_device(device)?;
2352 
2353                     // VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter
2354                     color_source.validate_device(device)?;
2355 
2356                     // VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter
2357                     color_destination.validate_device(device)?;
2358 
2359                     // VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter
2360                     alpha_op.validate_device(device)?;
2361 
2362                     // VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter
2363                     alpha_source.validate_device(device)?;
2364 
2365                     // VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter
2366                     alpha_destination.validate_device(device)?;
2367 
2368                     // VUID?
2369                     if !device.enabled_features().dual_src_blend
2370                         && [
2371                             color_source,
2372                             color_destination,
2373                             alpha_source,
2374                             alpha_destination,
2375                         ]
2376                         .into_iter()
2377                         .any(|blend_factor| {
2378                             matches!(
2379                                 blend_factor,
2380                                 BlendFactor::Src1Color
2381                                     | BlendFactor::OneMinusSrc1Color
2382                                     | BlendFactor::Src1Alpha
2383                                     | BlendFactor::OneMinusSrc1Alpha
2384                             )
2385                         })
2386                     {
2387                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
2388                             required_for: "`color_blend_state.attachments` has an element where \
2389                                 `blend` is `Some(blend)`, where `blend.color_source`, \
2390                                 `blend.color_destination`, `blend.alpha_source` or \
2391                                 `blend.alpha_destination` is `BlendFactor::Src1*`",
2392                             requires_one_of: RequiresOneOf {
2393                                 features: &["dual_src_blend"],
2394                                 ..Default::default()
2395                             },
2396                         });
2397                     }
2398 
2399                     let attachment_format = match render_pass {
2400                         PipelineRenderPassType::BeginRenderPass(subpass) => subpass
2401                             .subpass_desc()
2402                             .color_attachments[attachment_index]
2403                             .as_ref()
2404                             .and_then(|atch_ref| {
2405                                 subpass.render_pass().attachments()[atch_ref.attachment as usize]
2406                                     .format
2407                             }),
2408                         PipelineRenderPassType::BeginRendering(rendering_info) => {
2409                             rendering_info.color_attachment_formats[attachment_index]
2410                         }
2411                     };
2412 
2413                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06041
2414                     // VUID-VkGraphicsPipelineCreateInfo-renderPass-06062
2415                     // Use unchecked, because all validation has been done above or by the
2416                     // render pass creation.
2417                     if !attachment_format.map_or(false, |format| unsafe {
2418                         physical_device
2419                             .format_properties_unchecked(format)
2420                             .potential_format_features()
2421                             .intersects(FormatFeatures::COLOR_ATTACHMENT_BLEND)
2422                     }) {
2423                         return Err(
2424                             GraphicsPipelineCreationError::ColorAttachmentFormatBlendNotSupported {
2425                                 attachment_index: attachment_index as u32,
2426                             },
2427                         );
2428                     }
2429 
2430                     // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04454
2431                     // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04455
2432                     if device.enabled_extensions().khr_portability_subset
2433                         && !device.enabled_features().constant_alpha_color_blend_factors
2434                         && (matches!(
2435                             color_source,
2436                             BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha
2437                         ) || matches!(
2438                             color_destination,
2439                             BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha
2440                         ))
2441                     {
2442                         return Err(GraphicsPipelineCreationError::RequirementNotMet {
2443                             required_for: "this device is a portability subset device, and \
2444                                 `color_blend_state.attachments` has an element where `blend` is \
2445                                 `Some(blend)`, where \
2446                                 `blend.color_source` or `blend.color_destination` is \
2447                                 `BlendFactor::ConstantAlpha` or \
2448                                 `BlendFactor::OneMinusConstantAlpha`",
2449                             requires_one_of: RequiresOneOf {
2450                                 features: &["constant_alpha_color_blend_factors"],
2451                                 ..Default::default()
2452                             },
2453                         });
2454                     }
2455                 }
2456 
2457                 match color_write_enable {
2458                     StateMode::Fixed(enable) => {
2459                         // VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801
2460                         if !enable && !device.enabled_features().color_write_enable {
2461                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
2462                                 required_for: "`color_blend_state.attachments` has an element \
2463                                     where `color_write_enable` is `StateMode::Fixed(false)`",
2464                                 requires_one_of: RequiresOneOf {
2465                                     features: &["color_write_enable"],
2466                                     ..Default::default()
2467                                 },
2468                             });
2469                         }
2470                     }
2471                     StateMode::Dynamic => {
2472                         // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04800
2473                         if !device.enabled_features().color_write_enable {
2474                             return Err(GraphicsPipelineCreationError::RequirementNotMet {
2475                                 required_for: "`color_blend_state.attachments` has an element \
2476                                     where `color_write_enable` is `StateMode::Dynamic`",
2477                                 requires_one_of: RequiresOneOf {
2478                                     features: &["color_write_enable"],
2479                                     ..Default::default()
2480                                 },
2481                             });
2482                         }
2483                     }
2484                 }
2485             }
2486         }
2487 
2488         /*
2489             Generic shader checks
2490         */
2491 
2492         for stage_info in &shader_stages {
2493             // VUID-VkGraphicsPipelineCreateInfo-layout-00756
2494             pipeline_layout.ensure_compatible_with_shader(
2495                 stage_info.entry_point.descriptor_binding_requirements(),
2496                 stage_info.entry_point.push_constant_requirements(),
2497             )?;
2498 
2499             for (constant_id, reqs) in stage_info
2500                 .entry_point
2501                 .specialization_constant_requirements()
2502             {
2503                 let map_entry = stage_info
2504                     .specialization_map_entries
2505                     .iter()
2506                     .find(|desc| desc.constant_id == constant_id)
2507                     .ok_or(GraphicsPipelineCreationError::IncompatibleSpecializationConstants)?;
2508 
2509                 if map_entry.size as DeviceSize != reqs.size {
2510                     return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
2511                 }
2512             }
2513         }
2514 
2515         // VUID-VkGraphicsPipelineCreateInfo-pStages-00742
2516         // VUID-VkGraphicsPipelineCreateInfo-None-04889
2517         // TODO: this check is too strict; the output only has to be a superset, any variables
2518         // not used in the input of the next shader are just ignored.
2519         for (output, input) in shader_stages.iter().zip(shader_stages.iter().skip(1)) {
2520             if let Err(err) = input
2521                 .entry_point
2522                 .input_interface()
2523                 .matches(output.entry_point.output_interface())
2524             {
2525                 return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err));
2526             }
2527         }
2528 
2529         // TODO:
2530         // VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708
2531         // VUID-VkPipelineShaderStageCreateInfo-maxCullDistances-00709
2532         // VUID-VkPipelineShaderStageCreateInfo-maxCombinedClipAndCullDistances-00710
2533         // VUID-VkPipelineShaderStageCreateInfo-maxSampleMaskWords-00711
2534 
2535         // Dynamic states not handled yet:
2536         // - ViewportWScaling (VkPipelineViewportWScalingStateCreateInfoNV)
2537         // - SampleLocations (VkPipelineSampleLocationsStateCreateInfoEXT)
2538         // - ViewportShadingRatePalette (VkPipelineViewportShadingRateImageStateCreateInfoNV)
2539         // - ViewportCoarseSampleOrder (VkPipelineViewportCoarseSampleOrderStateCreateInfoNV)
2540         // - ExclusiveScissor (VkPipelineViewportExclusiveScissorStateCreateInfoNV)
2541         // - FragmentShadingRate (VkPipelineFragmentShadingRateStateCreateInfoKHR)
2542 
2543         Ok(())
2544     }
2545 
record_create( &self, device: &Device, pipeline_layout: &PipelineLayout, vertex_input_state: &VertexInputState, has: Has, ) -> Result< ( ash::vk::Pipeline, HashMap<(u32, u32), DescriptorBindingRequirements>, HashMap<DynamicState, bool>, HashMap<ShaderStage, ()>, Option<FragmentTestsStages>, ), GraphicsPipelineCreationError, >2546     unsafe fn record_create(
2547         &self,
2548         device: &Device,
2549         pipeline_layout: &PipelineLayout,
2550         vertex_input_state: &VertexInputState,
2551         has: Has,
2552     ) -> Result<
2553         (
2554             ash::vk::Pipeline,
2555             HashMap<(u32, u32), DescriptorBindingRequirements>,
2556             HashMap<DynamicState, bool>,
2557             HashMap<ShaderStage, ()>,
2558             Option<FragmentTestsStages>,
2559         ),
2560         GraphicsPipelineCreationError,
2561     > {
2562         let Self {
2563             render_pass,
2564             cache,
2565 
2566             vertex_shader,
2567             tessellation_shaders,
2568             geometry_shader,
2569             fragment_shader,
2570 
2571             vertex_input_state: _,
2572             input_assembly_state,
2573             tessellation_state,
2574             viewport_state,
2575             discard_rectangle_state,
2576             rasterization_state,
2577             multisample_state,
2578             depth_stencil_state,
2579             color_blend_state,
2580         } = self;
2581 
2582         let render_pass = render_pass.as_ref().unwrap();
2583 
2584         let mut descriptor_binding_requirements: HashMap<
2585             (u32, u32),
2586             DescriptorBindingRequirements,
2587         > = HashMap::default();
2588         let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default();
2589         let mut stages = HashMap::default();
2590         let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new();
2591         let mut fragment_tests_stages = None;
2592 
2593         /*
2594             Render pass
2595         */
2596 
2597         let mut render_pass_vk = ash::vk::RenderPass::null();
2598         let mut subpass_vk = 0;
2599         let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new();
2600         let mut rendering_create_info_vk = None;
2601 
2602         match render_pass {
2603             PipelineRenderPassType::BeginRenderPass(subpass) => {
2604                 render_pass_vk = subpass.render_pass().handle();
2605                 subpass_vk = subpass.index();
2606             }
2607             PipelineRenderPassType::BeginRendering(rendering_info) => {
2608                 let &PipelineRenderingCreateInfo {
2609                     view_mask,
2610                     ref color_attachment_formats,
2611                     depth_attachment_format,
2612                     stencil_attachment_format,
2613                     _ne: _,
2614                 } = rendering_info;
2615 
2616                 color_attachment_formats_vk.extend(
2617                     color_attachment_formats
2618                         .iter()
2619                         .map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into)),
2620                 );
2621 
2622                 let _ = rendering_create_info_vk.insert(ash::vk::PipelineRenderingCreateInfo {
2623                     view_mask,
2624                     color_attachment_count: color_attachment_formats_vk.len() as u32,
2625                     p_color_attachment_formats: color_attachment_formats_vk.as_ptr(),
2626                     depth_attachment_format: depth_attachment_format
2627                         .map_or(ash::vk::Format::UNDEFINED, Into::into),
2628                     stencil_attachment_format: stencil_attachment_format
2629                         .map_or(ash::vk::Format::UNDEFINED, Into::into),
2630                     ..Default::default()
2631                 });
2632             }
2633         }
2634 
2635         /*
2636             Vertex input state
2637         */
2638 
2639         let mut vertex_binding_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
2640         let mut vertex_attribute_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
2641         let mut vertex_binding_divisor_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
2642         let mut vertex_binding_divisor_state_vk = None;
2643         let mut vertex_input_state_vk = None;
2644         let mut input_assembly_state_vk = None;
2645 
2646         if has.vertex_input_state {
2647             // Vertex input state
2648             {
2649                 dynamic_state.insert(DynamicState::VertexInput, false);
2650 
2651                 let VertexInputState {
2652                     bindings,
2653                     attributes,
2654                 } = vertex_input_state;
2655 
2656                 vertex_binding_descriptions_vk.extend(bindings.iter().map(
2657                     |(&binding, binding_desc)| ash::vk::VertexInputBindingDescription {
2658                         binding,
2659                         stride: binding_desc.stride,
2660                         input_rate: binding_desc.input_rate.into(),
2661                     },
2662                 ));
2663 
2664                 vertex_attribute_descriptions_vk.extend(attributes.iter().map(
2665                     |(&location, attribute_desc)| ash::vk::VertexInputAttributeDescription {
2666                         location,
2667                         binding: attribute_desc.binding,
2668                         format: attribute_desc.format.into(),
2669                         offset: attribute_desc.offset,
2670                     },
2671                 ));
2672 
2673                 let vertex_input_state =
2674                     vertex_input_state_vk.insert(ash::vk::PipelineVertexInputStateCreateInfo {
2675                         flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(),
2676                         vertex_binding_description_count: vertex_binding_descriptions_vk.len()
2677                             as u32,
2678                         p_vertex_binding_descriptions: vertex_binding_descriptions_vk.as_ptr(),
2679                         vertex_attribute_description_count: vertex_attribute_descriptions_vk.len()
2680                             as u32,
2681                         p_vertex_attribute_descriptions: vertex_attribute_descriptions_vk.as_ptr(),
2682                         ..Default::default()
2683                     });
2684 
2685                 {
2686                     vertex_binding_divisor_descriptions_vk.extend(
2687                         bindings
2688                             .iter()
2689                             .filter_map(|(&binding, binding_desc)| match binding_desc.input_rate {
2690                                 VertexInputRate::Instance { divisor } if divisor != 1 => {
2691                                     Some((binding, divisor))
2692                                 }
2693                                 _ => None,
2694                             })
2695                             .map(|(binding, divisor)| {
2696                                 ash::vk::VertexInputBindingDivisorDescriptionEXT {
2697                                     binding,
2698                                     divisor,
2699                                 }
2700                             }),
2701                     );
2702 
2703                     // VUID-VkPipelineVertexInputDivisorStateCreateInfoEXT-vertexBindingDivisorCount-arraylength
2704                     if !vertex_binding_divisor_descriptions_vk.is_empty() {
2705                         vertex_input_state.p_next =
2706                             vertex_binding_divisor_state_vk.insert(
2707                                 ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT {
2708                                     vertex_binding_divisor_count:
2709                                         vertex_binding_divisor_descriptions_vk.len() as u32,
2710                                     p_vertex_binding_divisors:
2711                                         vertex_binding_divisor_descriptions_vk.as_ptr(),
2712                                     ..Default::default()
2713                                 },
2714                             ) as *const _ as *const _;
2715                     }
2716                 }
2717             }
2718 
2719             // Input assembly state
2720             {
2721                 let &InputAssemblyState {
2722                     topology,
2723                     primitive_restart_enable,
2724                 } = input_assembly_state;
2725 
2726                 let topology = match topology {
2727                     PartialStateMode::Fixed(topology) => {
2728                         dynamic_state.insert(DynamicState::PrimitiveTopology, false);
2729                         topology.into()
2730                     }
2731                     PartialStateMode::Dynamic(topology_class) => {
2732                         dynamic_state.insert(DynamicState::PrimitiveTopology, true);
2733                         topology_class.example().into()
2734                     }
2735                 };
2736 
2737                 let primitive_restart_enable = match primitive_restart_enable {
2738                     StateMode::Fixed(primitive_restart_enable) => {
2739                         dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false);
2740                         primitive_restart_enable as ash::vk::Bool32
2741                     }
2742                     StateMode::Dynamic => {
2743                         dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true);
2744                         Default::default()
2745                     }
2746                 };
2747 
2748                 let _ =
2749                     input_assembly_state_vk.insert(ash::vk::PipelineInputAssemblyStateCreateInfo {
2750                         flags: ash::vk::PipelineInputAssemblyStateCreateFlags::empty(),
2751                         topology,
2752                         primitive_restart_enable,
2753                         ..Default::default()
2754                     });
2755             }
2756         }
2757 
2758         /*
2759             Pre-rasterization shader state
2760         */
2761 
2762         let mut vertex_shader_specialization_vk = None;
2763         let mut tessellation_control_shader_specialization_vk = None;
2764         let mut tessellation_evaluation_shader_specialization_vk = None;
2765         let mut tessellation_state_vk = None;
2766         let mut geometry_shader_specialization_vk = None;
2767         let mut viewports_vk: SmallVec<[_; 2]> = SmallVec::new();
2768         let mut scissors_vk: SmallVec<[_; 2]> = SmallVec::new();
2769         let mut viewport_state_vk = None;
2770         let mut rasterization_line_state_vk = None;
2771         let mut rasterization_state_vk = None;
2772         let mut discard_rectangles: SmallVec<[_; 2]> = SmallVec::new();
2773         let mut discard_rectangle_state_vk = None;
2774 
2775         if has.pre_rasterization_shader_state {
2776             // Vertex shader
2777             if let Some((entry_point, specialization_data)) = vertex_shader {
2778                 let specialization_map_entries = Vss::descriptors();
2779                 let specialization_data = slice::from_raw_parts(
2780                     specialization_data as *const _ as *const u8,
2781                     size_of_val(specialization_data),
2782                 );
2783 
2784                 let specialization_info_vk =
2785                     vertex_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
2786                         map_entry_count: specialization_map_entries.len() as u32,
2787                         p_map_entries: specialization_map_entries.as_ptr() as *const _,
2788                         data_size: specialization_data.len(),
2789                         p_data: specialization_data.as_ptr() as *const _,
2790                     });
2791 
2792                 for (loc, reqs) in entry_point.descriptor_binding_requirements() {
2793                     match descriptor_binding_requirements.entry(loc) {
2794                         Entry::Occupied(entry) => {
2795                             entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
2796                         }
2797                         Entry::Vacant(entry) => {
2798                             entry.insert(reqs.clone());
2799                         }
2800                     }
2801                 }
2802 
2803                 stages.insert(ShaderStage::Vertex, ());
2804                 stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
2805                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
2806                     stage: ash::vk::ShaderStageFlags::VERTEX,
2807                     module: entry_point.module().handle(),
2808                     p_name: entry_point.name().as_ptr(),
2809                     p_specialization_info: specialization_info_vk as *const _,
2810                     ..Default::default()
2811                 });
2812             }
2813 
2814             // Tessellation shaders
2815             if let Some(tessellation_shaders) = tessellation_shaders {
2816                 {
2817                     let (entry_point, specialization_data) = &tessellation_shaders.control;
2818                     let specialization_map_entries = Tcss::descriptors();
2819                     let specialization_data = slice::from_raw_parts(
2820                         specialization_data as *const _ as *const u8,
2821                         size_of_val(specialization_data),
2822                     );
2823 
2824                     let specialization_info_vk = tessellation_control_shader_specialization_vk
2825                         .insert(ash::vk::SpecializationInfo {
2826                             map_entry_count: specialization_map_entries.len() as u32,
2827                             p_map_entries: specialization_map_entries.as_ptr() as *const _,
2828                             data_size: specialization_data.len(),
2829                             p_data: specialization_data.as_ptr() as *const _,
2830                         });
2831 
2832                     for (loc, reqs) in entry_point.descriptor_binding_requirements() {
2833                         match descriptor_binding_requirements.entry(loc) {
2834                             Entry::Occupied(entry) => {
2835                                 entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
2836                             }
2837                             Entry::Vacant(entry) => {
2838                                 entry.insert(reqs.clone());
2839                             }
2840                         }
2841                     }
2842 
2843                     stages.insert(ShaderStage::TessellationControl, ());
2844                     stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
2845                         flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
2846                         stage: ash::vk::ShaderStageFlags::TESSELLATION_CONTROL,
2847                         module: entry_point.module().handle(),
2848                         p_name: entry_point.name().as_ptr(),
2849                         p_specialization_info: specialization_info_vk as *const _,
2850                         ..Default::default()
2851                     });
2852                 }
2853 
2854                 {
2855                     let (entry_point, specialization_data) = &tessellation_shaders.evaluation;
2856                     let specialization_map_entries = Tess::descriptors();
2857                     let specialization_data = slice::from_raw_parts(
2858                         specialization_data as *const _ as *const u8,
2859                         size_of_val(specialization_data),
2860                     );
2861 
2862                     let specialization_info_vk = tessellation_evaluation_shader_specialization_vk
2863                         .insert(ash::vk::SpecializationInfo {
2864                             map_entry_count: specialization_map_entries.len() as u32,
2865                             p_map_entries: specialization_map_entries.as_ptr() as *const _,
2866                             data_size: specialization_data.len(),
2867                             p_data: specialization_data.as_ptr() as *const _,
2868                         });
2869 
2870                     for (loc, reqs) in entry_point.descriptor_binding_requirements() {
2871                         match descriptor_binding_requirements.entry(loc) {
2872                             Entry::Occupied(entry) => {
2873                                 entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
2874                             }
2875                             Entry::Vacant(entry) => {
2876                                 entry.insert(reqs.clone());
2877                             }
2878                         }
2879                     }
2880 
2881                     stages.insert(ShaderStage::TessellationEvaluation, ());
2882                     stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
2883                         flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
2884                         stage: ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION,
2885                         module: entry_point.module().handle(),
2886                         p_name: entry_point.name().as_ptr(),
2887                         p_specialization_info: specialization_info_vk as *const _,
2888                         ..Default::default()
2889                     });
2890                 }
2891             }
2892 
2893             // Geometry shader
2894             if let Some((entry_point, specialization_data)) = geometry_shader {
2895                 let specialization_map_entries = Gss::descriptors();
2896                 let specialization_data = slice::from_raw_parts(
2897                     specialization_data as *const _ as *const u8,
2898                     size_of_val(specialization_data),
2899                 );
2900 
2901                 let specialization_info_vk =
2902                     geometry_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
2903                         map_entry_count: specialization_map_entries.len() as u32,
2904                         p_map_entries: specialization_map_entries.as_ptr() as *const _,
2905                         data_size: specialization_data.len(),
2906                         p_data: specialization_data.as_ptr() as *const _,
2907                     });
2908 
2909                 for (loc, reqs) in entry_point.descriptor_binding_requirements() {
2910                     match descriptor_binding_requirements.entry(loc) {
2911                         Entry::Occupied(entry) => {
2912                             entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
2913                         }
2914                         Entry::Vacant(entry) => {
2915                             entry.insert(reqs.clone());
2916                         }
2917                     }
2918                 }
2919 
2920                 stages.insert(ShaderStage::Geometry, ());
2921                 stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
2922                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
2923                     stage: ash::vk::ShaderStageFlags::GEOMETRY,
2924                     module: entry_point.module().handle(),
2925                     p_name: entry_point.name().as_ptr(),
2926                     p_specialization_info: specialization_info_vk as *const _,
2927                     ..Default::default()
2928                 });
2929             }
2930 
2931             // Rasterization state
2932             {
2933                 let &RasterizationState {
2934                     depth_clamp_enable,
2935                     rasterizer_discard_enable,
2936                     polygon_mode,
2937                     cull_mode,
2938                     front_face,
2939                     depth_bias,
2940                     line_width,
2941                     line_rasterization_mode,
2942                     line_stipple,
2943                 } = rasterization_state;
2944 
2945                 let rasterizer_discard_enable = match rasterizer_discard_enable {
2946                     StateMode::Fixed(rasterizer_discard_enable) => {
2947                         dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false);
2948                         rasterizer_discard_enable as ash::vk::Bool32
2949                     }
2950                     StateMode::Dynamic => {
2951                         dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true);
2952                         ash::vk::FALSE
2953                     }
2954                 };
2955 
2956                 let cull_mode = match cull_mode {
2957                     StateMode::Fixed(cull_mode) => {
2958                         dynamic_state.insert(DynamicState::CullMode, false);
2959                         cull_mode.into()
2960                     }
2961                     StateMode::Dynamic => {
2962                         dynamic_state.insert(DynamicState::CullMode, true);
2963                         CullMode::default().into()
2964                     }
2965                 };
2966 
2967                 let front_face = match front_face {
2968                     StateMode::Fixed(front_face) => {
2969                         dynamic_state.insert(DynamicState::FrontFace, false);
2970                         front_face.into()
2971                     }
2972                     StateMode::Dynamic => {
2973                         dynamic_state.insert(DynamicState::FrontFace, true);
2974                         FrontFace::default().into()
2975                     }
2976                 };
2977 
2978                 let (
2979                     depth_bias_enable,
2980                     depth_bias_constant_factor,
2981                     depth_bias_clamp,
2982                     depth_bias_slope_factor,
2983                 ) = if let Some(depth_bias_state) = depth_bias {
2984                     if depth_bias_state.enable_dynamic {
2985                         dynamic_state.insert(DynamicState::DepthBiasEnable, true);
2986                     } else {
2987                         dynamic_state.insert(DynamicState::DepthBiasEnable, false);
2988                     }
2989 
2990                     let (constant_factor, clamp, slope_factor) = match depth_bias_state.bias {
2991                         StateMode::Fixed(bias) => {
2992                             dynamic_state.insert(DynamicState::DepthBias, false);
2993                             (bias.constant_factor, bias.clamp, bias.slope_factor)
2994                         }
2995                         StateMode::Dynamic => {
2996                             dynamic_state.insert(DynamicState::DepthBias, true);
2997                             (0.0, 0.0, 0.0)
2998                         }
2999                     };
3000 
3001                     (ash::vk::TRUE, constant_factor, clamp, slope_factor)
3002                 } else {
3003                     (ash::vk::FALSE, 0.0, 0.0, 0.0)
3004                 };
3005 
3006                 let line_width = match line_width {
3007                     StateMode::Fixed(line_width) => {
3008                         dynamic_state.insert(DynamicState::LineWidth, false);
3009                         line_width
3010                     }
3011                     StateMode::Dynamic => {
3012                         dynamic_state.insert(DynamicState::LineWidth, true);
3013                         1.0
3014                     }
3015                 };
3016 
3017                 let rasterization_state =
3018                     rasterization_state_vk.insert(ash::vk::PipelineRasterizationStateCreateInfo {
3019                         flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(),
3020                         depth_clamp_enable: depth_clamp_enable as ash::vk::Bool32,
3021                         rasterizer_discard_enable,
3022                         polygon_mode: polygon_mode.into(),
3023                         cull_mode,
3024                         front_face,
3025                         depth_bias_enable,
3026                         depth_bias_constant_factor,
3027                         depth_bias_clamp,
3028                         depth_bias_slope_factor,
3029                         line_width,
3030                         ..Default::default()
3031                     });
3032 
3033                 if device.enabled_extensions().ext_line_rasterization {
3034                     let (stippled_line_enable, line_stipple_factor, line_stipple_pattern) =
3035                         if let Some(line_stipple) = line_stipple {
3036                             let (factor, pattern) = match line_stipple {
3037                                 StateMode::Fixed(line_stipple) => {
3038                                     dynamic_state.insert(DynamicState::LineStipple, false);
3039                                     (line_stipple.factor, line_stipple.pattern)
3040                                 }
3041                                 StateMode::Dynamic => {
3042                                     dynamic_state.insert(DynamicState::LineStipple, true);
3043                                     (1, 0)
3044                                 }
3045                             };
3046 
3047                             (ash::vk::TRUE, factor, pattern)
3048                         } else {
3049                             (ash::vk::FALSE, 1, 0)
3050                         };
3051 
3052                     rasterization_state.p_next = rasterization_line_state_vk.insert(
3053                         ash::vk::PipelineRasterizationLineStateCreateInfoEXT {
3054                             line_rasterization_mode: line_rasterization_mode.into(),
3055                             stippled_line_enable,
3056                             line_stipple_factor,
3057                             line_stipple_pattern,
3058                             ..Default::default()
3059                         },
3060                     ) as *const _ as *const _;
3061                 }
3062             }
3063 
3064             // Discard rectangle state
3065             if device.enabled_extensions().ext_discard_rectangles {
3066                 let DiscardRectangleState { mode, rectangles } = discard_rectangle_state;
3067 
3068                 let discard_rectangle_count = match rectangles {
3069                     PartialStateMode::Fixed(rectangles) => {
3070                         dynamic_state.insert(DynamicState::DiscardRectangle, false);
3071                         discard_rectangles.extend(rectangles.iter().map(|&rect| rect.into()));
3072 
3073                         discard_rectangles.len() as u32
3074                     }
3075                     PartialStateMode::Dynamic(count) => {
3076                         dynamic_state.insert(DynamicState::DiscardRectangle, true);
3077 
3078                         *count
3079                     }
3080                 };
3081 
3082                 let _ = discard_rectangle_state_vk.insert(
3083                     ash::vk::PipelineDiscardRectangleStateCreateInfoEXT {
3084                         flags: ash::vk::PipelineDiscardRectangleStateCreateFlagsEXT::empty(),
3085                         discard_rectangle_mode: (*mode).into(),
3086                         discard_rectangle_count,
3087                         p_discard_rectangles: discard_rectangles.as_ptr(),
3088                         ..Default::default()
3089                     },
3090                 );
3091             }
3092         }
3093 
3094         // Tessellation state
3095         if has.tessellation_state {
3096             let &TessellationState {
3097                 patch_control_points,
3098             } = tessellation_state;
3099 
3100             let patch_control_points = match patch_control_points {
3101                 StateMode::Fixed(patch_control_points) => {
3102                     dynamic_state.insert(DynamicState::PatchControlPoints, false);
3103                     patch_control_points
3104                 }
3105                 StateMode::Dynamic => {
3106                     dynamic_state.insert(DynamicState::PatchControlPoints, true);
3107                     Default::default()
3108                 }
3109             };
3110 
3111             let _ = tessellation_state_vk.insert(ash::vk::PipelineTessellationStateCreateInfo {
3112                 flags: ash::vk::PipelineTessellationStateCreateFlags::empty(),
3113                 patch_control_points,
3114                 ..Default::default()
3115             });
3116         }
3117 
3118         // Viewport state
3119         if has.viewport_state {
3120             let (viewport_count, scissor_count) = match viewport_state {
3121                 ViewportState::Fixed { data } => {
3122                     let count = data.len() as u32;
3123                     viewports_vk.extend(data.iter().map(|e| e.0.clone().into()));
3124                     dynamic_state.insert(DynamicState::Viewport, false);
3125                     dynamic_state.insert(DynamicState::ViewportWithCount, false);
3126 
3127                     scissors_vk.extend(data.iter().map(|e| e.1.into()));
3128                     dynamic_state.insert(DynamicState::Scissor, false);
3129                     dynamic_state.insert(DynamicState::ScissorWithCount, false);
3130 
3131                     (count, count)
3132                 }
3133                 ViewportState::FixedViewport {
3134                     viewports,
3135                     scissor_count_dynamic,
3136                 } => {
3137                     let viewport_count = viewports.len() as u32;
3138                     viewports_vk.extend(viewports.iter().map(|e| e.clone().into()));
3139                     dynamic_state.insert(DynamicState::Viewport, false);
3140                     dynamic_state.insert(DynamicState::ViewportWithCount, false);
3141 
3142                     let scissor_count = if *scissor_count_dynamic {
3143                         dynamic_state.insert(DynamicState::Scissor, false);
3144                         dynamic_state.insert(DynamicState::ScissorWithCount, true);
3145                         0
3146                     } else {
3147                         dynamic_state.insert(DynamicState::Scissor, true);
3148                         dynamic_state.insert(DynamicState::ScissorWithCount, false);
3149                         viewport_count
3150                     };
3151 
3152                     (viewport_count, scissor_count)
3153                 }
3154                 ViewportState::FixedScissor {
3155                     scissors,
3156                     viewport_count_dynamic,
3157                 } => {
3158                     let scissor_count = scissors.len() as u32;
3159                     scissors_vk.extend(scissors.iter().map(|&e| e.into()));
3160                     dynamic_state.insert(DynamicState::Scissor, false);
3161                     dynamic_state.insert(DynamicState::ScissorWithCount, false);
3162 
3163                     let viewport_count = if *viewport_count_dynamic {
3164                         dynamic_state.insert(DynamicState::Viewport, false);
3165                         dynamic_state.insert(DynamicState::ViewportWithCount, true);
3166                         0
3167                     } else {
3168                         dynamic_state.insert(DynamicState::Viewport, true);
3169                         dynamic_state.insert(DynamicState::ViewportWithCount, false);
3170                         scissor_count
3171                     };
3172 
3173                     (viewport_count, scissor_count)
3174                 }
3175                 &ViewportState::Dynamic {
3176                     count,
3177                     viewport_count_dynamic,
3178                     scissor_count_dynamic,
3179                 } => {
3180                     let viewport_count = if viewport_count_dynamic {
3181                         dynamic_state.insert(DynamicState::Viewport, false);
3182                         dynamic_state.insert(DynamicState::ViewportWithCount, true);
3183 
3184                         0
3185                     } else {
3186                         dynamic_state.insert(DynamicState::Viewport, true);
3187                         dynamic_state.insert(DynamicState::ViewportWithCount, false);
3188 
3189                         count
3190                     };
3191                     let scissor_count = if scissor_count_dynamic {
3192                         dynamic_state.insert(DynamicState::Scissor, false);
3193                         dynamic_state.insert(DynamicState::ScissorWithCount, true);
3194 
3195                         0
3196                     } else {
3197                         dynamic_state.insert(DynamicState::Scissor, true);
3198                         dynamic_state.insert(DynamicState::ScissorWithCount, false);
3199 
3200                         count
3201                     };
3202 
3203                     (viewport_count, scissor_count)
3204                 }
3205             };
3206 
3207             let _ = viewport_state_vk.insert(ash::vk::PipelineViewportStateCreateInfo {
3208                 flags: ash::vk::PipelineViewportStateCreateFlags::empty(),
3209                 viewport_count,
3210                 p_viewports: if viewports_vk.is_empty() {
3211                     ptr::null()
3212                 } else {
3213                     viewports_vk.as_ptr()
3214                 }, // validation layer crashes if you just pass the pointer
3215                 scissor_count,
3216                 p_scissors: if scissors_vk.is_empty() {
3217                     ptr::null()
3218                 } else {
3219                     scissors_vk.as_ptr()
3220                 }, // validation layer crashes if you just pass the pointer
3221                 ..Default::default()
3222             });
3223         }
3224 
3225         /*
3226             Fragment shader state
3227         */
3228 
3229         let mut fragment_shader_specialization_vk = None;
3230         let mut depth_stencil_state_vk = None;
3231 
3232         if has.fragment_shader_state {
3233             // Fragment shader
3234             if let Some((entry_point, specialization_data)) = fragment_shader {
3235                 let specialization_map_entries = Fss::descriptors();
3236                 let specialization_data = slice::from_raw_parts(
3237                     specialization_data as *const _ as *const u8,
3238                     size_of_val(specialization_data),
3239                 );
3240 
3241                 let specialization_info_vk =
3242                     fragment_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
3243                         map_entry_count: specialization_map_entries.len() as u32,
3244                         p_map_entries: specialization_map_entries.as_ptr() as *const _,
3245                         data_size: specialization_data.len(),
3246                         p_data: specialization_data.as_ptr() as *const _,
3247                     });
3248 
3249                 for (loc, reqs) in entry_point.descriptor_binding_requirements() {
3250                     match descriptor_binding_requirements.entry(loc) {
3251                         Entry::Occupied(entry) => {
3252                             entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
3253                         }
3254                         Entry::Vacant(entry) => {
3255                             entry.insert(reqs.clone());
3256                         }
3257                     }
3258                 }
3259 
3260                 stages.insert(ShaderStage::Fragment, ());
3261                 stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
3262                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
3263                     stage: ash::vk::ShaderStageFlags::FRAGMENT,
3264                     module: entry_point.module().handle(),
3265                     p_name: entry_point.name().as_ptr(),
3266                     p_specialization_info: specialization_info_vk as *const _,
3267                     ..Default::default()
3268                 });
3269                 fragment_tests_stages = match entry_point.execution() {
3270                     ShaderExecution::Fragment(FragmentShaderExecution {
3271                         fragment_tests_stages,
3272                         ..
3273                     }) => Some(*fragment_tests_stages),
3274                     _ => unreachable!(),
3275                 };
3276             }
3277         }
3278 
3279         // Depth/stencil state
3280         if has.depth_stencil_state {
3281             let DepthStencilState {
3282                 depth,
3283                 depth_bounds,
3284                 stencil,
3285             } = depth_stencil_state;
3286 
3287             let (depth_test_enable, depth_write_enable, depth_compare_op) =
3288                 if let Some(depth_state) = depth {
3289                     let &DepthState {
3290                         enable_dynamic,
3291                         write_enable,
3292                         compare_op,
3293                     } = depth_state;
3294 
3295                     if enable_dynamic {
3296                         dynamic_state.insert(DynamicState::DepthTestEnable, true);
3297                     } else {
3298                         dynamic_state.insert(DynamicState::DepthTestEnable, false);
3299                     }
3300 
3301                     let write_enable = match write_enable {
3302                         StateMode::Fixed(write_enable) => {
3303                             dynamic_state.insert(DynamicState::DepthWriteEnable, false);
3304                             write_enable as ash::vk::Bool32
3305                         }
3306                         StateMode::Dynamic => {
3307                             dynamic_state.insert(DynamicState::DepthWriteEnable, true);
3308                             ash::vk::TRUE
3309                         }
3310                     };
3311 
3312                     let compare_op = match compare_op {
3313                         StateMode::Fixed(compare_op) => {
3314                             dynamic_state.insert(DynamicState::DepthCompareOp, false);
3315                             compare_op.into()
3316                         }
3317                         StateMode::Dynamic => {
3318                             dynamic_state.insert(DynamicState::DepthCompareOp, true);
3319                             ash::vk::CompareOp::ALWAYS
3320                         }
3321                     };
3322 
3323                     (ash::vk::TRUE, write_enable, compare_op)
3324                 } else {
3325                     (ash::vk::FALSE, ash::vk::FALSE, ash::vk::CompareOp::ALWAYS)
3326                 };
3327 
3328             let (depth_bounds_test_enable, min_depth_bounds, max_depth_bounds) =
3329                 if let Some(depth_bounds_state) = depth_bounds {
3330                     let DepthBoundsState {
3331                         enable_dynamic,
3332                         bounds,
3333                     } = depth_bounds_state;
3334 
3335                     if *enable_dynamic {
3336                         dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true);
3337                     } else {
3338                         dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false);
3339                     }
3340 
3341                     let (min_bounds, max_bounds) = match bounds.clone() {
3342                         StateMode::Fixed(bounds) => {
3343                             dynamic_state.insert(DynamicState::DepthBounds, false);
3344                             bounds.into_inner()
3345                         }
3346                         StateMode::Dynamic => {
3347                             dynamic_state.insert(DynamicState::DepthBounds, true);
3348                             (0.0, 1.0)
3349                         }
3350                     };
3351 
3352                     (ash::vk::TRUE, min_bounds, max_bounds)
3353                 } else {
3354                     (ash::vk::FALSE, 0.0, 1.0)
3355                 };
3356 
3357             let (stencil_test_enable, front, back) = if let Some(stencil_state) = stencil {
3358                 let StencilState {
3359                     enable_dynamic,
3360                     front,
3361                     back,
3362                 } = stencil_state;
3363 
3364                 if *enable_dynamic {
3365                     dynamic_state.insert(DynamicState::StencilTestEnable, true);
3366                 } else {
3367                     dynamic_state.insert(DynamicState::StencilTestEnable, false);
3368                 }
3369 
3370                 match (front.ops, back.ops) {
3371                     (StateMode::Fixed(_), StateMode::Fixed(_)) => {
3372                         dynamic_state.insert(DynamicState::StencilOp, false);
3373                     }
3374                     (StateMode::Dynamic, StateMode::Dynamic) => {
3375                         dynamic_state.insert(DynamicState::StencilOp, true);
3376                     }
3377                     _ => unreachable!(),
3378                 };
3379 
3380                 match (front.compare_mask, back.compare_mask) {
3381                     (StateMode::Fixed(_), StateMode::Fixed(_)) => {
3382                         dynamic_state.insert(DynamicState::StencilCompareMask, false);
3383                     }
3384                     (StateMode::Dynamic, StateMode::Dynamic) => {
3385                         dynamic_state.insert(DynamicState::StencilCompareMask, true);
3386                     }
3387                     _ => unreachable!(),
3388                 };
3389 
3390                 match (front.write_mask, back.write_mask) {
3391                     (StateMode::Fixed(_), StateMode::Fixed(_)) => {
3392                         dynamic_state.insert(DynamicState::StencilWriteMask, false);
3393                     }
3394                     (StateMode::Dynamic, StateMode::Dynamic) => {
3395                         dynamic_state.insert(DynamicState::StencilWriteMask, true);
3396                     }
3397                     _ => unreachable!(),
3398                 };
3399 
3400                 match (front.reference, back.reference) {
3401                     (StateMode::Fixed(_), StateMode::Fixed(_)) => {
3402                         dynamic_state.insert(DynamicState::StencilReference, false);
3403                     }
3404                     (StateMode::Dynamic, StateMode::Dynamic) => {
3405                         dynamic_state.insert(DynamicState::StencilReference, true);
3406                     }
3407                     _ => unreachable!(),
3408                 };
3409 
3410                 let [front, back] = [front, back].map(|stencil_op_state| {
3411                     let &StencilOpState {
3412                         ops,
3413                         compare_mask,
3414                         write_mask,
3415                         reference,
3416                     } = stencil_op_state;
3417 
3418                     let ops = match ops {
3419                         StateMode::Fixed(x) => x,
3420                         StateMode::Dynamic => Default::default(),
3421                     };
3422                     let compare_mask = match compare_mask {
3423                         StateMode::Fixed(x) => x,
3424                         StateMode::Dynamic => Default::default(),
3425                     };
3426                     let write_mask = match write_mask {
3427                         StateMode::Fixed(x) => x,
3428                         StateMode::Dynamic => Default::default(),
3429                     };
3430                     let reference = match reference {
3431                         StateMode::Fixed(x) => x,
3432                         StateMode::Dynamic => Default::default(),
3433                     };
3434 
3435                     ash::vk::StencilOpState {
3436                         fail_op: ops.fail_op.into(),
3437                         pass_op: ops.pass_op.into(),
3438                         depth_fail_op: ops.depth_fail_op.into(),
3439                         compare_op: ops.compare_op.into(),
3440                         compare_mask,
3441                         write_mask,
3442                         reference,
3443                     }
3444                 });
3445 
3446                 (ash::vk::TRUE, front, back)
3447             } else {
3448                 (ash::vk::FALSE, Default::default(), Default::default())
3449             };
3450 
3451             let _ = depth_stencil_state_vk.insert(ash::vk::PipelineDepthStencilStateCreateInfo {
3452                 flags: ash::vk::PipelineDepthStencilStateCreateFlags::empty(),
3453                 depth_test_enable,
3454                 depth_write_enable,
3455                 depth_compare_op,
3456                 depth_bounds_test_enable,
3457                 stencil_test_enable,
3458                 front,
3459                 back,
3460                 min_depth_bounds,
3461                 max_depth_bounds,
3462                 ..Default::default()
3463             });
3464         }
3465 
3466         /*
3467             Fragment output state
3468         */
3469 
3470         let mut multisample_state_vk = None;
3471         let mut color_blend_attachments_vk: SmallVec<[_; 4]> = SmallVec::new();
3472         let mut color_write_enables_vk: SmallVec<[_; 4]> = SmallVec::new();
3473         let mut color_write_vk = None;
3474         let mut color_blend_state_vk = None;
3475 
3476         if has.fragment_output_state {
3477             // Multisample state
3478             {
3479                 let &MultisampleState {
3480                     rasterization_samples,
3481                     sample_shading,
3482                     ref sample_mask,
3483                     alpha_to_coverage_enable,
3484                     alpha_to_one_enable,
3485                 } = multisample_state;
3486 
3487                 let (sample_shading_enable, min_sample_shading) =
3488                     if let Some(min_sample_shading) = sample_shading {
3489                         (ash::vk::TRUE, min_sample_shading)
3490                     } else {
3491                         (ash::vk::FALSE, 0.0)
3492                     };
3493 
3494                 let _ = multisample_state_vk.insert(ash::vk::PipelineMultisampleStateCreateInfo {
3495                     flags: ash::vk::PipelineMultisampleStateCreateFlags::empty(),
3496                     rasterization_samples: rasterization_samples.into(),
3497                     sample_shading_enable,
3498                     min_sample_shading,
3499                     p_sample_mask: sample_mask as _,
3500                     alpha_to_coverage_enable: alpha_to_coverage_enable as ash::vk::Bool32,
3501                     alpha_to_one_enable: alpha_to_one_enable as ash::vk::Bool32,
3502                     ..Default::default()
3503                 });
3504             }
3505         }
3506 
3507         // Color blend state
3508         if has.color_blend_state {
3509             let &ColorBlendState {
3510                 logic_op,
3511                 ref attachments,
3512                 blend_constants,
3513             } = color_blend_state;
3514 
3515             color_blend_attachments_vk.extend(attachments.iter().map(
3516                 |color_blend_attachment_state| {
3517                     let &ColorBlendAttachmentState {
3518                         blend,
3519                         color_write_mask,
3520                         color_write_enable: _,
3521                     } = color_blend_attachment_state;
3522 
3523                     let blend = if let Some(blend) = blend {
3524                         blend.into()
3525                     } else {
3526                         Default::default()
3527                     };
3528 
3529                     ash::vk::PipelineColorBlendAttachmentState {
3530                         color_write_mask: color_write_mask.into(),
3531                         ..blend
3532                     }
3533                 },
3534             ));
3535 
3536             let (logic_op_enable, logic_op) = if let Some(logic_op) = logic_op {
3537                 let logic_op = match logic_op {
3538                     StateMode::Fixed(logic_op) => {
3539                         dynamic_state.insert(DynamicState::LogicOp, false);
3540                         logic_op.into()
3541                     }
3542                     StateMode::Dynamic => {
3543                         dynamic_state.insert(DynamicState::LogicOp, true);
3544                         Default::default()
3545                     }
3546                 };
3547 
3548                 (ash::vk::TRUE, logic_op)
3549             } else {
3550                 (ash::vk::FALSE, Default::default())
3551             };
3552 
3553             let blend_constants = match blend_constants {
3554                 StateMode::Fixed(blend_constants) => {
3555                     dynamic_state.insert(DynamicState::BlendConstants, false);
3556                     blend_constants
3557                 }
3558                 StateMode::Dynamic => {
3559                     dynamic_state.insert(DynamicState::BlendConstants, true);
3560                     Default::default()
3561                 }
3562             };
3563 
3564             let mut color_blend_state_vk =
3565                 color_blend_state_vk.insert(ash::vk::PipelineColorBlendStateCreateInfo {
3566                     flags: ash::vk::PipelineColorBlendStateCreateFlags::empty(),
3567                     logic_op_enable,
3568                     logic_op,
3569                     attachment_count: color_blend_attachments_vk.len() as u32,
3570                     p_attachments: color_blend_attachments_vk.as_ptr(),
3571                     blend_constants,
3572                     ..Default::default()
3573                 });
3574 
3575             if device.enabled_extensions().ext_color_write_enable {
3576                 color_write_enables_vk.extend(attachments.iter().map(
3577                     |color_blend_attachment_state| {
3578                         let &ColorBlendAttachmentState {
3579                             blend: _,
3580                             color_write_mask: _,
3581                             color_write_enable,
3582                         } = color_blend_attachment_state;
3583 
3584                         match color_write_enable {
3585                             StateMode::Fixed(enable) => {
3586                                 dynamic_state.insert(DynamicState::ColorWriteEnable, false);
3587                                 enable as ash::vk::Bool32
3588                             }
3589                             StateMode::Dynamic => {
3590                                 dynamic_state.insert(DynamicState::ColorWriteEnable, true);
3591                                 ash::vk::TRUE
3592                             }
3593                         }
3594                     },
3595                 ));
3596 
3597                 color_blend_state_vk.p_next =
3598                     color_write_vk.insert(ash::vk::PipelineColorWriteCreateInfoEXT {
3599                         attachment_count: color_write_enables_vk.len() as u32,
3600                         p_color_write_enables: color_write_enables_vk.as_ptr(),
3601                         ..Default::default()
3602                     }) as *const _ as *const _;
3603             }
3604         }
3605 
3606         /*
3607             Dynamic state
3608         */
3609 
3610         let mut dynamic_state_list: SmallVec<[_; 4]> = SmallVec::new();
3611         let mut dynamic_state_vk = None;
3612 
3613         {
3614             dynamic_state_list.extend(
3615                 dynamic_state
3616                     .iter()
3617                     .filter(|(_, d)| **d)
3618                     .map(|(&state, _)| state.into()),
3619             );
3620 
3621             if !dynamic_state_list.is_empty() {
3622                 let _ = dynamic_state_vk.insert(ash::vk::PipelineDynamicStateCreateInfo {
3623                     flags: ash::vk::PipelineDynamicStateCreateFlags::empty(),
3624                     dynamic_state_count: dynamic_state_list.len() as u32,
3625                     p_dynamic_states: dynamic_state_list.as_ptr(),
3626                     ..Default::default()
3627                 });
3628             }
3629         }
3630 
3631         /*
3632             Create
3633         */
3634 
3635         let mut create_info = ash::vk::GraphicsPipelineCreateInfo {
3636             flags: ash::vk::PipelineCreateFlags::empty(), // TODO: some flags are available but none are critical
3637             stage_count: stages_vk.len() as u32,
3638             p_stages: stages_vk.as_ptr(),
3639             p_vertex_input_state: vertex_input_state_vk
3640                 .as_ref()
3641                 .map(|p| p as *const _)
3642                 .unwrap_or(ptr::null()),
3643             p_input_assembly_state: input_assembly_state_vk
3644                 .as_ref()
3645                 .map(|p| p as *const _)
3646                 .unwrap_or(ptr::null()),
3647             p_tessellation_state: tessellation_state_vk
3648                 .as_ref()
3649                 .map(|p| p as *const _)
3650                 .unwrap_or(ptr::null()),
3651             p_viewport_state: viewport_state_vk
3652                 .as_ref()
3653                 .map(|p| p as *const _)
3654                 .unwrap_or(ptr::null()),
3655             p_rasterization_state: rasterization_state_vk
3656                 .as_ref()
3657                 .map(|p| p as *const _)
3658                 .unwrap_or(ptr::null()),
3659             p_multisample_state: multisample_state_vk
3660                 .as_ref()
3661                 .map(|p| p as *const _)
3662                 .unwrap_or(ptr::null()),
3663             p_depth_stencil_state: depth_stencil_state_vk
3664                 .as_ref()
3665                 .map(|p| p as *const _)
3666                 .unwrap_or(ptr::null()),
3667             p_color_blend_state: color_blend_state_vk
3668                 .as_ref()
3669                 .map(|p| p as *const _)
3670                 .unwrap_or(ptr::null()),
3671             p_dynamic_state: dynamic_state_vk
3672                 .as_ref()
3673                 .map(|s| s as *const _)
3674                 .unwrap_or(ptr::null()),
3675             layout: pipeline_layout.handle(),
3676             render_pass: render_pass_vk,
3677             subpass: subpass_vk,
3678             base_pipeline_handle: ash::vk::Pipeline::null(), // TODO:
3679             base_pipeline_index: -1,                         // TODO:
3680             ..Default::default()
3681         };
3682 
3683         if let Some(info) = discard_rectangle_state_vk.as_mut() {
3684             info.p_next = create_info.p_next;
3685             create_info.p_next = info as *const _ as *const _;
3686         }
3687 
3688         if let Some(info) = rendering_create_info_vk.as_mut() {
3689             info.p_next = create_info.p_next;
3690             create_info.p_next = info as *const _ as *const _;
3691         }
3692 
3693         let cache_handle = match cache.as_ref() {
3694             Some(cache) => cache.handle(),
3695             None => ash::vk::PipelineCache::null(),
3696         };
3697 
3698         let handle = {
3699             let fns = device.fns();
3700             let mut output = MaybeUninit::uninit();
3701             (fns.v1_0.create_graphics_pipelines)(
3702                 device.handle(),
3703                 cache_handle,
3704                 1,
3705                 &create_info,
3706                 ptr::null(),
3707                 output.as_mut_ptr(),
3708             )
3709             .result()
3710             .map_err(VulkanError::from)?;
3711 
3712             output.assume_init()
3713         };
3714 
3715         // Some drivers return `VK_SUCCESS` but provide a null handle if they
3716         // fail to create the pipeline (due to invalid shaders, etc)
3717         // This check ensures that we don't create an invalid `GraphicsPipeline` instance
3718         if handle == ash::vk::Pipeline::null() {
3719             panic!("vkCreateGraphicsPipelines provided a NULL handle");
3720         }
3721 
3722         Ok((
3723             handle,
3724             descriptor_binding_requirements,
3725             dynamic_state,
3726             stages,
3727             fragment_tests_stages,
3728         ))
3729     }
3730 
3731     // TODO: add build_with_cache method
3732 }
3733 
3734 struct ShaderStageInfo<'a> {
3735     entry_point: &'a EntryPoint<'a>,
3736     specialization_map_entries: &'a [SpecializationMapEntry],
3737     _specialization_data: &'a [u8],
3738 }
3739 
3740 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
3741     GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
3742 {
3743     // TODO: add pipeline derivate system
3744 
3745     /// Sets the vertex shader to use.
3746     // TODO: correct specialization constants
vertex_shader<'vs2, Vss2>( self, shader: EntryPoint<'vs2>, specialization_constants: Vss2, ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss> where Vss2: SpecializationConstants,3747     pub fn vertex_shader<'vs2, Vss2>(
3748         self,
3749         shader: EntryPoint<'vs2>,
3750         specialization_constants: Vss2,
3751     ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss>
3752     where
3753         Vss2: SpecializationConstants,
3754     {
3755         GraphicsPipelineBuilder {
3756             render_pass: self.render_pass,
3757             cache: self.cache,
3758 
3759             vertex_shader: Some((shader, specialization_constants)),
3760             tessellation_shaders: self.tessellation_shaders,
3761             geometry_shader: self.geometry_shader,
3762             fragment_shader: self.fragment_shader,
3763 
3764             vertex_input_state: self.vertex_input_state,
3765             input_assembly_state: self.input_assembly_state,
3766             tessellation_state: self.tessellation_state,
3767             viewport_state: self.viewport_state,
3768             discard_rectangle_state: self.discard_rectangle_state,
3769             rasterization_state: self.rasterization_state,
3770             multisample_state: self.multisample_state,
3771             depth_stencil_state: self.depth_stencil_state,
3772             color_blend_state: self.color_blend_state,
3773         }
3774     }
3775 
3776     /// Sets the tessellation shaders to use.
3777     // TODO: correct specialization constants
tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>( self, control_shader: EntryPoint<'tcs2>, control_specialization_constants: Tcss2, evaluation_shader: EntryPoint<'tes2>, evaluation_specialization_constants: Tess2, ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss> where Tcss2: SpecializationConstants, Tess2: SpecializationConstants,3778     pub fn tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>(
3779         self,
3780         control_shader: EntryPoint<'tcs2>,
3781         control_specialization_constants: Tcss2,
3782         evaluation_shader: EntryPoint<'tes2>,
3783         evaluation_specialization_constants: Tess2,
3784     ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss>
3785     where
3786         Tcss2: SpecializationConstants,
3787         Tess2: SpecializationConstants,
3788     {
3789         GraphicsPipelineBuilder {
3790             render_pass: self.render_pass,
3791             cache: self.cache,
3792 
3793             vertex_shader: self.vertex_shader,
3794             tessellation_shaders: Some(TessellationShaders {
3795                 control: (control_shader, control_specialization_constants),
3796                 evaluation: (evaluation_shader, evaluation_specialization_constants),
3797             }),
3798             geometry_shader: self.geometry_shader,
3799             fragment_shader: self.fragment_shader,
3800 
3801             vertex_input_state: self.vertex_input_state,
3802             input_assembly_state: self.input_assembly_state,
3803             tessellation_state: self.tessellation_state,
3804             viewport_state: self.viewport_state,
3805             discard_rectangle_state: self.discard_rectangle_state,
3806             rasterization_state: self.rasterization_state,
3807             multisample_state: self.multisample_state,
3808             depth_stencil_state: self.depth_stencil_state,
3809             color_blend_state: self.color_blend_state,
3810         }
3811     }
3812 
3813     /// Sets the geometry shader to use.
3814     // TODO: correct specialization constants
geometry_shader<'gs2, Gss2>( self, shader: EntryPoint<'gs2>, specialization_constants: Gss2, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss> where Gss2: SpecializationConstants,3815     pub fn geometry_shader<'gs2, Gss2>(
3816         self,
3817         shader: EntryPoint<'gs2>,
3818         specialization_constants: Gss2,
3819     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss>
3820     where
3821         Gss2: SpecializationConstants,
3822     {
3823         GraphicsPipelineBuilder {
3824             render_pass: self.render_pass,
3825             cache: self.cache,
3826 
3827             vertex_shader: self.vertex_shader,
3828             tessellation_shaders: self.tessellation_shaders,
3829             geometry_shader: Some((shader, specialization_constants)),
3830             fragment_shader: self.fragment_shader,
3831 
3832             vertex_input_state: self.vertex_input_state,
3833             input_assembly_state: self.input_assembly_state,
3834             tessellation_state: self.tessellation_state,
3835             viewport_state: self.viewport_state,
3836             discard_rectangle_state: self.discard_rectangle_state,
3837             rasterization_state: self.rasterization_state,
3838             multisample_state: self.multisample_state,
3839             depth_stencil_state: self.depth_stencil_state,
3840             color_blend_state: self.color_blend_state,
3841         }
3842     }
3843 
3844     /// Sets the fragment shader to use.
3845     ///
3846     /// The fragment shader is run once for each pixel that is covered by each primitive.
3847     // TODO: correct specialization constants
fragment_shader<'fs2, Fss2>( self, shader: EntryPoint<'fs2>, specialization_constants: Fss2, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2> where Fss2: SpecializationConstants,3848     pub fn fragment_shader<'fs2, Fss2>(
3849         self,
3850         shader: EntryPoint<'fs2>,
3851         specialization_constants: Fss2,
3852     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2>
3853     where
3854         Fss2: SpecializationConstants,
3855     {
3856         GraphicsPipelineBuilder {
3857             render_pass: self.render_pass,
3858             cache: self.cache,
3859 
3860             vertex_shader: self.vertex_shader,
3861             tessellation_shaders: self.tessellation_shaders,
3862             geometry_shader: self.geometry_shader,
3863             fragment_shader: Some((shader, specialization_constants)),
3864 
3865             vertex_input_state: self.vertex_input_state,
3866             input_assembly_state: self.input_assembly_state,
3867             tessellation_state: self.tessellation_state,
3868             viewport_state: self.viewport_state,
3869             discard_rectangle_state: self.discard_rectangle_state,
3870             rasterization_state: self.rasterization_state,
3871             multisample_state: self.multisample_state,
3872             depth_stencil_state: self.depth_stencil_state,
3873             color_blend_state: self.color_blend_state,
3874         }
3875     }
3876 
3877     /// Sets the vertex input state.
3878     ///
3879     /// The default value is [`VertexInputState::default()`].
vertex_input_state<T>( self, vertex_input_state: T, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss> where T: VertexDefinition,3880     pub fn vertex_input_state<T>(
3881         self,
3882         vertex_input_state: T,
3883     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss>
3884     where
3885         T: VertexDefinition,
3886     {
3887         GraphicsPipelineBuilder {
3888             render_pass: self.render_pass,
3889             cache: self.cache,
3890 
3891             vertex_shader: self.vertex_shader,
3892             tessellation_shaders: self.tessellation_shaders,
3893             geometry_shader: self.geometry_shader,
3894             fragment_shader: self.fragment_shader,
3895 
3896             vertex_input_state,
3897             input_assembly_state: self.input_assembly_state,
3898             tessellation_state: self.tessellation_state,
3899             viewport_state: self.viewport_state,
3900             discard_rectangle_state: self.discard_rectangle_state,
3901             rasterization_state: self.rasterization_state,
3902             multisample_state: self.multisample_state,
3903             depth_stencil_state: self.depth_stencil_state,
3904             color_blend_state: self.color_blend_state,
3905         }
3906     }
3907 
3908     /// Sets the input assembly state.
3909     ///
3910     /// The default value is [`InputAssemblyState::default()`].
3911     #[inline]
input_assembly_state(mut self, input_assembly_state: InputAssemblyState) -> Self3912     pub fn input_assembly_state(mut self, input_assembly_state: InputAssemblyState) -> Self {
3913         self.input_assembly_state = input_assembly_state;
3914         self
3915     }
3916 
3917     /// Sets the tessellation state. This is required if the pipeline contains tessellation shaders,
3918     /// and ignored otherwise.
3919     ///
3920     /// The default value is [`TessellationState::default()`].
3921     #[inline]
tessellation_state(mut self, tessellation_state: TessellationState) -> Self3922     pub fn tessellation_state(mut self, tessellation_state: TessellationState) -> Self {
3923         self.tessellation_state = tessellation_state;
3924         self
3925     }
3926 
3927     /// Sets the viewport state.
3928     ///
3929     /// The default value is [`ViewportState::default()`].
3930     #[inline]
viewport_state(mut self, viewport_state: ViewportState) -> Self3931     pub fn viewport_state(mut self, viewport_state: ViewportState) -> Self {
3932         self.viewport_state = viewport_state;
3933         self
3934     }
3935 
3936     /// Sets the discard rectangle state.
3937     ///
3938     /// The default value is [`DiscardRectangleState::default()`].
3939     #[inline]
discard_rectangle_state( mut self, discard_rectangle_state: DiscardRectangleState, ) -> Self3940     pub fn discard_rectangle_state(
3941         mut self,
3942         discard_rectangle_state: DiscardRectangleState,
3943     ) -> Self {
3944         self.discard_rectangle_state = discard_rectangle_state;
3945         self
3946     }
3947 
3948     /// Sets the rasterization state.
3949     ///
3950     /// The default value is [`RasterizationState::default()`].
3951     #[inline]
rasterization_state(mut self, rasterization_state: RasterizationState) -> Self3952     pub fn rasterization_state(mut self, rasterization_state: RasterizationState) -> Self {
3953         self.rasterization_state = rasterization_state;
3954         self
3955     }
3956 
3957     /// Sets the multisample state.
3958     ///
3959     /// The default value is [`MultisampleState::default()`].
3960     #[inline]
multisample_state(mut self, multisample_state: MultisampleState) -> Self3961     pub fn multisample_state(mut self, multisample_state: MultisampleState) -> Self {
3962         self.multisample_state = multisample_state;
3963         self
3964     }
3965 
3966     /// Sets the depth/stencil state.
3967     ///
3968     /// The default value is [`DepthStencilState::default()`].
3969     #[inline]
depth_stencil_state(mut self, depth_stencil_state: DepthStencilState) -> Self3970     pub fn depth_stencil_state(mut self, depth_stencil_state: DepthStencilState) -> Self {
3971         self.depth_stencil_state = depth_stencil_state;
3972         self
3973     }
3974 
3975     /// Sets the color blend state.
3976     ///
3977     /// The default value is [`ColorBlendState::default()`].
3978     #[inline]
color_blend_state(mut self, color_blend_state: ColorBlendState) -> Self3979     pub fn color_blend_state(mut self, color_blend_state: ColorBlendState) -> Self {
3980         self.color_blend_state = color_blend_state;
3981         self
3982     }
3983 
3984     /// Sets the tessellation shaders stage as disabled. This is the default.
3985     #[deprecated(since = "0.27.0")]
3986     #[inline]
tessellation_shaders_disabled(mut self) -> Self3987     pub fn tessellation_shaders_disabled(mut self) -> Self {
3988         self.tessellation_shaders = None;
3989         self
3990     }
3991 
3992     /// Sets the geometry shader stage as disabled. This is the default.
3993     #[deprecated(since = "0.27.0")]
3994     #[inline]
geometry_shader_disabled(mut self) -> Self3995     pub fn geometry_shader_disabled(mut self) -> Self {
3996         self.geometry_shader = None;
3997         self
3998     }
3999 
4000     /// Sets whether primitive restart is enabled.
4001     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4002     #[inline]
primitive_restart(mut self, enabled: bool) -> Self4003     pub fn primitive_restart(mut self, enabled: bool) -> Self {
4004         self.input_assembly_state.primitive_restart_enable = StateMode::Fixed(enabled);
4005         self
4006     }
4007 
4008     /// Sets the topology of the primitives that are expected by the pipeline.
4009     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4010     #[inline]
primitive_topology(mut self, topology: PrimitiveTopology) -> Self4011     pub fn primitive_topology(mut self, topology: PrimitiveTopology) -> Self {
4012         self.input_assembly_state.topology = PartialStateMode::Fixed(topology);
4013         self
4014     }
4015 
4016     /// Sets the topology of the primitives to a list of points.
4017     ///
4018     /// > **Note**: This is equivalent to
4019     /// > `self.primitive_topology(PrimitiveTopology::PointList)`.
4020     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4021     #[inline]
point_list(self) -> Self4022     pub fn point_list(self) -> Self {
4023         self.primitive_topology(PrimitiveTopology::PointList)
4024     }
4025 
4026     /// Sets the topology of the primitives to a list of lines.
4027     ///
4028     /// > **Note**: This is equivalent to
4029     /// > `self.primitive_topology(PrimitiveTopology::LineList)`.
4030     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4031     #[inline]
line_list(self) -> Self4032     pub fn line_list(self) -> Self {
4033         self.primitive_topology(PrimitiveTopology::LineList)
4034     }
4035 
4036     /// Sets the topology of the primitives to a line strip.
4037     ///
4038     /// > **Note**: This is equivalent to
4039     /// > `self.primitive_topology(PrimitiveTopology::LineStrip)`.
4040     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4041     #[inline]
line_strip(self) -> Self4042     pub fn line_strip(self) -> Self {
4043         self.primitive_topology(PrimitiveTopology::LineStrip)
4044     }
4045 
4046     /// Sets the topology of the primitives to a list of triangles. Note that this is the default.
4047     ///
4048     /// > **Note**: This is equivalent to
4049     /// > `self.primitive_topology(PrimitiveTopology::TriangleList)`.
4050     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4051     #[inline]
triangle_list(self) -> Self4052     pub fn triangle_list(self) -> Self {
4053         self.primitive_topology(PrimitiveTopology::TriangleList)
4054     }
4055 
4056     /// Sets the topology of the primitives to a triangle strip.
4057     ///
4058     /// > **Note**: This is equivalent to
4059     /// > `self.primitive_topology(PrimitiveTopology::TriangleStrip)`.
4060     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4061     #[inline]
triangle_strip(self) -> Self4062     pub fn triangle_strip(self) -> Self {
4063         self.primitive_topology(PrimitiveTopology::TriangleStrip)
4064     }
4065 
4066     /// Sets the topology of the primitives to a fan of triangles.
4067     ///
4068     /// > **Note**: This is equivalent to
4069     /// > `self.primitive_topology(PrimitiveTopology::TriangleFan)`.
4070     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4071     #[inline]
triangle_fan(self) -> Self4072     pub fn triangle_fan(self) -> Self {
4073         self.primitive_topology(PrimitiveTopology::TriangleFan)
4074     }
4075 
4076     /// Sets the topology of the primitives to a list of lines with adjacency information.
4077     ///
4078     /// > **Note**: This is equivalent to
4079     /// > `self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)`.
4080     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4081     #[inline]
line_list_with_adjacency(self) -> Self4082     pub fn line_list_with_adjacency(self) -> Self {
4083         self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)
4084     }
4085 
4086     /// Sets the topology of the primitives to a line strip with adjacency information.
4087     ///
4088     /// > **Note**: This is equivalent to
4089     /// > `self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)`.
4090     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4091     #[inline]
line_strip_with_adjacency(self) -> Self4092     pub fn line_strip_with_adjacency(self) -> Self {
4093         self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)
4094     }
4095 
4096     /// Sets the topology of the primitives to a list of triangles with adjacency information.
4097     ///
4098     /// > **Note**: This is equivalent to
4099     /// > `self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)`.
4100     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4101     #[inline]
triangle_list_with_adjacency(self) -> Self4102     pub fn triangle_list_with_adjacency(self) -> Self {
4103         self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)
4104     }
4105 
4106     /// Sets the topology of the primitives to a triangle strip with adjacency information`
4107     ///
4108     /// > **Note**: This is equivalent to
4109     /// > `self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)`.
4110     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4111     #[inline]
triangle_strip_with_adjacency(self) -> Self4112     pub fn triangle_strip_with_adjacency(self) -> Self {
4113         self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)
4114     }
4115 
4116     /// Sets the topology of the primitives to a list of patches. Can only be used and must be used
4117     /// with a tessellation shader.
4118     ///
4119     /// > **Note**: This is equivalent to
4120     /// > `self.primitive_topology(PrimitiveTopology::PatchList)`.
4121     #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
4122     #[inline]
patch_list(self) -> Self4123     pub fn patch_list(self) -> Self {
4124         self.primitive_topology(PrimitiveTopology::PatchList)
4125     }
4126 
4127     /// Sets the viewports to some value, and the scissor boxes to boxes that always cover the
4128     /// whole viewport.
4129     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
viewports<I>(self, viewports: I) -> Self where I: IntoIterator<Item = Viewport>,4130     pub fn viewports<I>(self, viewports: I) -> Self
4131     where
4132         I: IntoIterator<Item = Viewport>,
4133     {
4134         self.viewports_scissors(viewports.into_iter().map(|v| (v, Scissor::irrelevant())))
4135     }
4136 
4137     /// Sets the characteristics of viewports and scissor boxes in advance.
4138     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
viewports_scissors<I>(mut self, viewports: I) -> Self where I: IntoIterator<Item = (Viewport, Scissor)>,4139     pub fn viewports_scissors<I>(mut self, viewports: I) -> Self
4140     where
4141         I: IntoIterator<Item = (Viewport, Scissor)>,
4142     {
4143         self.viewport_state = ViewportState::Fixed {
4144             data: viewports.into_iter().collect(),
4145         };
4146         self
4147     }
4148 
4149     /// Sets the scissor boxes to some values, and viewports to dynamic. The viewports will
4150     /// need to be set before drawing.
4151     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self where I: IntoIterator<Item = Scissor>,4152     pub fn viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self
4153     where
4154         I: IntoIterator<Item = Scissor>,
4155     {
4156         self.viewport_state = ViewportState::FixedScissor {
4157             scissors: scissors.into_iter().collect(),
4158             viewport_count_dynamic: false,
4159         };
4160         self
4161     }
4162 
4163     /// Sets the viewports to dynamic, and the scissor boxes to boxes that always cover the whole
4164     /// viewport. The viewports will need to be set before drawing.
4165     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
4166     #[inline]
viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self4167     pub fn viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self {
4168         self.viewport_state = ViewportState::FixedScissor {
4169             scissors: (0..num).map(|_| Scissor::irrelevant()).collect(),
4170             viewport_count_dynamic: false,
4171         };
4172         self
4173     }
4174 
4175     /// Sets the viewports to some values, and scissor boxes to dynamic. The scissor boxes will
4176     /// need to be set before drawing.
4177     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self where I: IntoIterator<Item = Viewport>,4178     pub fn viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self
4179     where
4180         I: IntoIterator<Item = Viewport>,
4181     {
4182         self.viewport_state = ViewportState::FixedViewport {
4183             viewports: viewports.into_iter().collect(),
4184             scissor_count_dynamic: false,
4185         };
4186         self
4187     }
4188 
4189     /// Sets the viewports and scissor boxes to dynamic. They will both need to be set before
4190     /// drawing.
4191     #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
4192     #[inline]
viewports_scissors_dynamic(mut self, count: u32) -> Self4193     pub fn viewports_scissors_dynamic(mut self, count: u32) -> Self {
4194         self.viewport_state = ViewportState::Dynamic {
4195             count,
4196             viewport_count_dynamic: false,
4197             scissor_count_dynamic: false,
4198         };
4199         self
4200     }
4201 
4202     /// If true, then the depth value of the vertices will be clamped to the range `[0.0 ; 1.0]`.
4203     /// If false, fragments whose depth is outside of this range will be discarded before the
4204     /// fragment shader even runs.
4205     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4206     #[inline]
depth_clamp(mut self, clamp: bool) -> Self4207     pub fn depth_clamp(mut self, clamp: bool) -> Self {
4208         self.rasterization_state.depth_clamp_enable = clamp;
4209         self
4210     }
4211 
4212     /// Sets the front-facing faces to counter-clockwise faces. This is the default.
4213     ///
4214     /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
4215     /// as facing their front. Otherwise they will be considered as facing their back.
4216     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4217     #[inline]
front_face_counter_clockwise(mut self) -> Self4218     pub fn front_face_counter_clockwise(mut self) -> Self {
4219         self.rasterization_state.front_face = StateMode::Fixed(FrontFace::CounterClockwise);
4220         self
4221     }
4222 
4223     /// Sets the front-facing faces to clockwise faces.
4224     ///
4225     /// Triangles whose vertices are oriented clockwise on the screen will be considered
4226     /// as facing their front. Otherwise they will be considered as facing their back.
4227     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4228     #[inline]
front_face_clockwise(mut self) -> Self4229     pub fn front_face_clockwise(mut self) -> Self {
4230         self.rasterization_state.front_face = StateMode::Fixed(FrontFace::Clockwise);
4231         self
4232     }
4233 
4234     /// Sets backface culling as disabled. This is the default.
4235     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4236     #[inline]
cull_mode_disabled(mut self) -> Self4237     pub fn cull_mode_disabled(mut self) -> Self {
4238         self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::None);
4239         self
4240     }
4241 
4242     /// Sets backface culling to front faces. The front faces (as chosen with the `front_face_*`
4243     /// methods) will be discarded by the GPU when drawing.
4244     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4245     #[inline]
cull_mode_front(mut self) -> Self4246     pub fn cull_mode_front(mut self) -> Self {
4247         self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Front);
4248         self
4249     }
4250 
4251     /// Sets backface culling to back faces. Faces that are not facing the front (as chosen with
4252     /// the `front_face_*` methods) will be discarded by the GPU when drawing.
4253     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4254     #[inline]
cull_mode_back(mut self) -> Self4255     pub fn cull_mode_back(mut self) -> Self {
4256         self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Back);
4257         self
4258     }
4259 
4260     /// Sets backface culling to both front and back faces. All the faces will be discarded.
4261     ///
4262     /// > **Note**: This option exists for the sake of completeness. It has no known practical
4263     /// > usage.
4264     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4265     #[inline]
cull_mode_front_and_back(mut self) -> Self4266     pub fn cull_mode_front_and_back(mut self) -> Self {
4267         self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::FrontAndBack);
4268         self
4269     }
4270 
4271     /// Sets the polygon mode to "fill". This is the default.
4272     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4273     #[inline]
polygon_mode_fill(mut self) -> Self4274     pub fn polygon_mode_fill(mut self) -> Self {
4275         self.rasterization_state.polygon_mode = PolygonMode::Fill;
4276         self
4277     }
4278 
4279     /// Sets the polygon mode to "line". Triangles will each be turned into three lines.
4280     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4281     #[inline]
polygon_mode_line(mut self) -> Self4282     pub fn polygon_mode_line(mut self) -> Self {
4283         self.rasterization_state.polygon_mode = PolygonMode::Line;
4284         self
4285     }
4286 
4287     /// Sets the polygon mode to "point". Triangles and lines will each be turned into three points.
4288     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4289     #[inline]
polygon_mode_point(mut self) -> Self4290     pub fn polygon_mode_point(mut self) -> Self {
4291         self.rasterization_state.polygon_mode = PolygonMode::Point;
4292         self
4293     }
4294 
4295     /// Sets the width of the lines, if the GPU needs to draw lines. The default is `1.0`.
4296     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4297     #[inline]
line_width(mut self, value: f32) -> Self4298     pub fn line_width(mut self, value: f32) -> Self {
4299         self.rasterization_state.line_width = StateMode::Fixed(value);
4300         self
4301     }
4302 
4303     /// Sets the width of the lines as dynamic, which means that you will need to set this value
4304     /// when drawing.
4305     #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
4306     #[inline]
line_width_dynamic(mut self) -> Self4307     pub fn line_width_dynamic(mut self) -> Self {
4308         self.rasterization_state.line_width = StateMode::Dynamic;
4309         self
4310     }
4311 
4312     /// Disables sample shading. The fragment shader will only be run once per fragment (ie. per
4313     /// pixel) and not once by sample. The output will then be copied in all of the covered
4314     /// samples.
4315     ///
4316     /// Sample shading is disabled by default.
4317     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
4318     #[inline]
sample_shading_disabled(mut self) -> Self4319     pub fn sample_shading_disabled(mut self) -> Self {
4320         self.multisample_state.sample_shading = None;
4321         self
4322     }
4323 
4324     /// Enables sample shading. The fragment shader will be run once per sample at the borders of
4325     /// the object you're drawing.
4326     ///
4327     /// Enabling sampling shading requires the `sample_rate_shading` feature to be enabled on the
4328     /// device.
4329     ///
4330     /// The `min_fract` parameter is the minimum fraction of samples shading. For example if its
4331     /// value is 0.5, then the fragment shader will run for at least half of the samples. The other
4332     /// half of the samples will get their values determined automatically.
4333     ///
4334     /// Sample shading is disabled by default.
4335     ///
4336     /// # Panics
4337     ///
4338     /// - Panics if `min_fract` is not between 0.0 and 1.0.
4339     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
4340     #[inline]
sample_shading_enabled(mut self, min_fract: f32) -> Self4341     pub fn sample_shading_enabled(mut self, min_fract: f32) -> Self {
4342         assert!((0.0..=1.0).contains(&min_fract));
4343         self.multisample_state.sample_shading = Some(min_fract);
4344         self
4345     }
4346 
4347     // TODO: doc
4348     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
alpha_to_coverage_disabled(mut self) -> Self4349     pub fn alpha_to_coverage_disabled(mut self) -> Self {
4350         self.multisample_state.alpha_to_coverage_enable = false;
4351         self
4352     }
4353 
4354     // TODO: doc
4355     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
alpha_to_coverage_enabled(mut self) -> Self4356     pub fn alpha_to_coverage_enabled(mut self) -> Self {
4357         self.multisample_state.alpha_to_coverage_enable = true;
4358         self
4359     }
4360 
4361     /// Disables alpha-to-one.
4362     ///
4363     /// Alpha-to-one is disabled by default.
4364     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
4365     #[inline]
alpha_to_one_disabled(mut self) -> Self4366     pub fn alpha_to_one_disabled(mut self) -> Self {
4367         self.multisample_state.alpha_to_one_enable = false;
4368         self
4369     }
4370 
4371     /// Enables alpha-to-one. The alpha component of the first color output of the fragment shader
4372     /// will be replaced by the value `1.0`.
4373     ///
4374     /// Enabling alpha-to-one requires the `alpha_to_one` feature to be enabled on the device.
4375     ///
4376     /// Alpha-to-one is disabled by default.
4377     #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
4378     #[inline]
alpha_to_one_enabled(mut self) -> Self4379     pub fn alpha_to_one_enabled(mut self) -> Self {
4380         self.multisample_state.alpha_to_one_enable = true;
4381         self
4382     }
4383 
4384     /// Sets the depth/stencil state.
4385     #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
4386     #[inline]
depth_stencil(self, depth_stencil_state: DepthStencilState) -> Self4387     pub fn depth_stencil(self, depth_stencil_state: DepthStencilState) -> Self {
4388         self.depth_stencil_state(depth_stencil_state)
4389     }
4390 
4391     /// Sets the depth/stencil tests as disabled.
4392     ///
4393     /// > **Note**: This is a shortcut for all the other `depth_*` and `depth_stencil_*` methods
4394     /// > of the builder.
4395     #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
4396     #[inline]
depth_stencil_disabled(mut self) -> Self4397     pub fn depth_stencil_disabled(mut self) -> Self {
4398         self.depth_stencil_state = DepthStencilState::disabled();
4399         self
4400     }
4401 
4402     /// Sets the depth/stencil tests as a simple depth test and no stencil test.
4403     ///
4404     /// > **Note**: This is a shortcut for setting the depth test to `Less`, the depth write Into
4405     /// > ` true` and disable the stencil test.
4406     #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
4407     #[inline]
depth_stencil_simple_depth(mut self) -> Self4408     pub fn depth_stencil_simple_depth(mut self) -> Self {
4409         self.depth_stencil_state = DepthStencilState::simple_depth_test();
4410         self
4411     }
4412 
4413     /// Sets whether the depth buffer will be written.
4414     #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
4415     #[inline]
depth_write(mut self, write: bool) -> Self4416     pub fn depth_write(mut self, write: bool) -> Self {
4417         let depth_state = self
4418             .depth_stencil_state
4419             .depth
4420             .get_or_insert(Default::default());
4421         depth_state.write_enable = StateMode::Fixed(write);
4422         self
4423     }
4424 
4425     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4426     // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
4427     // for self.color_blend_state.attachments.len() == 1
4428     #[inline]
blend_collective(mut self, blend: AttachmentBlend) -> Self4429     pub fn blend_collective(mut self, blend: AttachmentBlend) -> Self {
4430         self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
4431             blend: Some(blend),
4432             color_write_mask: ColorComponents::all(),
4433             color_write_enable: StateMode::Fixed(true),
4434         }];
4435         self
4436     }
4437 
4438     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
blend_individual<I>(mut self, blend: I) -> Self where I: IntoIterator<Item = AttachmentBlend>,4439     pub fn blend_individual<I>(mut self, blend: I) -> Self
4440     where
4441         I: IntoIterator<Item = AttachmentBlend>,
4442     {
4443         self.color_blend_state.attachments = blend
4444             .into_iter()
4445             .map(|x| ColorBlendAttachmentState {
4446                 blend: Some(x),
4447                 color_write_mask: ColorComponents::all(),
4448                 color_write_enable: StateMode::Fixed(true),
4449             })
4450             .collect();
4451         self
4452     }
4453 
4454     /// Each fragment shader output will have its value directly written to the framebuffer
4455     /// attachment. This is the default.
4456     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4457     // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
4458     // for self.color_blend_state.attachments.len() == 1
4459     #[inline]
blend_pass_through(mut self) -> Self4460     pub fn blend_pass_through(mut self) -> Self {
4461         self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
4462             blend: None,
4463             color_write_mask: ColorComponents::all(),
4464             color_write_enable: StateMode::Fixed(true),
4465         }];
4466         self
4467     }
4468 
4469     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4470     // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
4471     // for self.color_blend_state.attachments.len() == 1
4472     #[inline]
blend_alpha_blending(mut self) -> Self4473     pub fn blend_alpha_blending(mut self) -> Self {
4474         self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
4475             blend: Some(AttachmentBlend::alpha()),
4476             color_write_mask: ColorComponents::all(),
4477             color_write_enable: StateMode::Fixed(true),
4478         }];
4479         self
4480     }
4481 
4482     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4483     #[inline]
blend_logic_op(mut self, logic_op: LogicOp) -> Self4484     pub fn blend_logic_op(mut self, logic_op: LogicOp) -> Self {
4485         self.color_blend_state.logic_op = Some(StateMode::Fixed(logic_op));
4486         self
4487     }
4488 
4489     /// Sets the logic operation as disabled. This is the default.
4490     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4491     #[inline]
blend_logic_op_disabled(mut self) -> Self4492     pub fn blend_logic_op_disabled(mut self) -> Self {
4493         self.color_blend_state.logic_op = None;
4494         self
4495     }
4496 
4497     /// Sets the blend constant. The default is `[0.0, 0.0, 0.0, 0.0]`.
4498     ///
4499     /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
4500     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4501     #[inline]
blend_constants(mut self, constants: [f32; 4]) -> Self4502     pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
4503         self.color_blend_state.blend_constants = StateMode::Fixed(constants);
4504         self
4505     }
4506 
4507     /// Sets the blend constant value as dynamic. Its value will need to be set before drawing.
4508     ///
4509     /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
4510     #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
4511     #[inline]
blend_constants_dynamic(mut self) -> Self4512     pub fn blend_constants_dynamic(mut self) -> Self {
4513         self.color_blend_state.blend_constants = StateMode::Dynamic;
4514         self
4515     }
4516 
4517     /// Sets the render pass subpass to use.
render_pass(self, render_pass: impl Into<PipelineRenderPassType>) -> Self4518     pub fn render_pass(self, render_pass: impl Into<PipelineRenderPassType>) -> Self {
4519         GraphicsPipelineBuilder {
4520             render_pass: Some(render_pass.into()),
4521             cache: self.cache,
4522 
4523             vertex_shader: self.vertex_shader,
4524             tessellation_shaders: self.tessellation_shaders,
4525             geometry_shader: self.geometry_shader,
4526             fragment_shader: self.fragment_shader,
4527 
4528             vertex_input_state: self.vertex_input_state,
4529             input_assembly_state: self.input_assembly_state,
4530             tessellation_state: self.tessellation_state,
4531             viewport_state: self.viewport_state,
4532             rasterization_state: self.rasterization_state,
4533             multisample_state: self.multisample_state,
4534             depth_stencil_state: self.depth_stencil_state,
4535             color_blend_state: self.color_blend_state,
4536 
4537             discard_rectangle_state: self.discard_rectangle_state,
4538         }
4539     }
4540 
4541     /// Enable caching of this pipeline via a PipelineCache object.
4542     ///
4543     /// If this pipeline already exists in the cache it will be used, if this is a new
4544     /// pipeline it will be inserted into the cache. The implementation handles the
4545     /// PipelineCache.
4546     #[inline]
build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self4547     pub fn build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self {
4548         self.cache = Some(pipeline_cache);
4549         self
4550     }
4551 }
4552 
4553 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> Clone
4554     for GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
4555 where
4556     Vdef: Clone,
4557     Vss: Clone,
4558     Tcss: Clone,
4559     Tess: Clone,
4560     Gss: Clone,
4561     Fss: Clone,
4562 {
clone(&self) -> Self4563     fn clone(&self) -> Self {
4564         GraphicsPipelineBuilder {
4565             render_pass: self.render_pass.clone(),
4566             cache: self.cache.clone(),
4567 
4568             vertex_shader: self.vertex_shader.clone(),
4569             tessellation_shaders: self.tessellation_shaders.clone(),
4570             geometry_shader: self.geometry_shader.clone(),
4571             fragment_shader: self.fragment_shader.clone(),
4572 
4573             vertex_input_state: self.vertex_input_state.clone(),
4574             input_assembly_state: self.input_assembly_state,
4575             tessellation_state: self.tessellation_state,
4576             viewport_state: self.viewport_state.clone(),
4577             rasterization_state: self.rasterization_state.clone(),
4578             multisample_state: self.multisample_state,
4579             depth_stencil_state: self.depth_stencil_state.clone(),
4580             color_blend_state: self.color_blend_state.clone(),
4581 
4582             discard_rectangle_state: self.discard_rectangle_state.clone(),
4583         }
4584     }
4585 }
4586