• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::check_errors;
15 use crate::descriptor_set::layout::DescriptorSetDesc;
16 use crate::descriptor_set::layout::DescriptorSetLayout;
17 use crate::device::Device;
18 use crate::image::SampleCount;
19 use crate::pipeline::blend::AttachmentBlend;
20 use crate::pipeline::blend::AttachmentsBlend;
21 use crate::pipeline::blend::Blend;
22 use crate::pipeline::blend::LogicOp;
23 use crate::pipeline::cache::PipelineCache;
24 use crate::pipeline::depth_stencil::Compare;
25 use crate::pipeline::depth_stencil::DepthBounds;
26 use crate::pipeline::depth_stencil::DepthStencil;
27 use crate::pipeline::graphics_pipeline::GraphicsPipeline;
28 use crate::pipeline::graphics_pipeline::GraphicsPipelineCreationError;
29 use crate::pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
30 use crate::pipeline::input_assembly::PrimitiveTopology;
31 use crate::pipeline::layout::PipelineLayout;
32 use crate::pipeline::layout::PipelineLayoutPcRange;
33 use crate::pipeline::raster::CullMode;
34 use crate::pipeline::raster::DepthBiasControl;
35 use crate::pipeline::raster::FrontFace;
36 use crate::pipeline::raster::PolygonMode;
37 use crate::pipeline::raster::Rasterization;
38 use crate::pipeline::shader::EntryPointAbstract;
39 use crate::pipeline::shader::GraphicsEntryPoint;
40 use crate::pipeline::shader::GraphicsShaderType;
41 use crate::pipeline::shader::SpecializationConstants;
42 use crate::pipeline::vertex::BufferlessDefinition;
43 use crate::pipeline::vertex::BuffersDefinition;
44 use crate::pipeline::vertex::Vertex;
45 use crate::pipeline::vertex::VertexDefinition;
46 use crate::pipeline::vertex::VertexInputRate;
47 use crate::pipeline::viewport::Scissor;
48 use crate::pipeline::viewport::Viewport;
49 use crate::pipeline::viewport::ViewportsState;
50 use crate::render_pass::Subpass;
51 use crate::OomError;
52 use crate::VulkanObject;
53 use smallvec::SmallVec;
54 use std::collections::hash_map::{Entry, HashMap};
55 use std::mem;
56 use std::mem::MaybeUninit;
57 use std::ptr;
58 use std::sync::Arc;
59 use std::u32;
60 
61 /// Prototype for a `GraphicsPipeline`.
62 // TODO: we can optimize this by filling directly the raw vk structs
63 pub struct GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> {
64     vertex_definition: Vdef,
65     vertex_shader: Option<(GraphicsEntryPoint<'vs>, Vss)>,
66     input_assembly: ash::vk::PipelineInputAssemblyStateCreateInfo,
67     // Note: the `input_assembly_topology` member is temporary in order to not lose information
68     // about the number of patches per primitive.
69     input_assembly_topology: PrimitiveTopology,
70     tessellation: Option<TessInfo<'tcs, 'tes, Tcss, Tess>>,
71     geometry_shader: Option<(GraphicsEntryPoint<'gs>, Gss)>,
72     viewport: Option<ViewportsState>,
73     raster: Rasterization,
74     multisample: ash::vk::PipelineMultisampleStateCreateInfo,
75     fragment_shader: Option<(GraphicsEntryPoint<'fs>, Fss)>,
76     depth_stencil: DepthStencil,
77     blend: Blend,
78     subpass: Option<Subpass>,
79     cache: Option<Arc<PipelineCache>>,
80 }
81 
82 // Additional parameters if tessellation is used.
83 #[derive(Clone, Debug)]
84 struct TessInfo<'tcs, 'tes, Tcss, Tess> {
85     tessellation_control_shader: (GraphicsEntryPoint<'tcs>, Tcss),
86     tessellation_evaluation_shader: (GraphicsEntryPoint<'tes>, Tess),
87 }
88 
89 impl
90     GraphicsPipelineBuilder<
91         'static,
92         'static,
93         'static,
94         'static,
95         'static,
96         BufferlessDefinition,
97         (),
98         (),
99         (),
100         (),
101         (),
102     >
103 {
104     /// Builds a new empty builder.
new() -> Self105     pub(super) fn new() -> Self {
106         GraphicsPipelineBuilder {
107             vertex_definition: BufferlessDefinition,
108             vertex_shader: None,
109             input_assembly: ash::vk::PipelineInputAssemblyStateCreateInfo {
110                 topology: PrimitiveTopology::TriangleList.into(),
111                 ..Default::default()
112             },
113             input_assembly_topology: PrimitiveTopology::TriangleList,
114             tessellation: None,
115             geometry_shader: None,
116             viewport: None,
117             raster: Default::default(),
118             multisample: ash::vk::PipelineMultisampleStateCreateInfo::default(),
119             fragment_shader: None,
120             depth_stencil: DepthStencil::disabled(),
121             blend: Blend::pass_through(),
122             subpass: None,
123             cache: None,
124         }
125     }
126 }
127 
128 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
129     GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
130 where
131     Vdef: VertexDefinition,
132     Vss: SpecializationConstants,
133     Tcss: SpecializationConstants,
134     Tess: SpecializationConstants,
135     Gss: SpecializationConstants,
136     Fss: SpecializationConstants,
137 {
138     /// Builds the graphics pipeline, using an inferred a pipeline layout.
build( self, device: Arc<Device>, ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError>139     pub fn build(
140         self,
141         device: Arc<Device>,
142     ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
143         self.with_auto_layout(device, &[])
144     }
145 
146     /// Builds the graphics pipeline, using an inferred pipeline layout with some dynamic buffers.
147     ///
148     /// Configures the inferred layout for each descriptor `(set, binding)` in `dynamic_buffers` to accept dynamic
149     /// buffers.
with_auto_layout( self, device: Arc<Device>, dynamic_buffers: &[(usize, usize)], ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError>150     pub fn with_auto_layout(
151         self,
152         device: Arc<Device>,
153         dynamic_buffers: &[(usize, usize)],
154     ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
155         let (descriptor_set_layout_descs, push_constant_ranges) = {
156             let stages: SmallVec<[&GraphicsEntryPoint; 5]> = std::array::IntoIter::new([
157                 self.vertex_shader.as_ref().map(|s| &s.0),
158                 self.tessellation
159                     .as_ref()
160                     .map(|s| &s.tessellation_control_shader.0),
161                 self.tessellation
162                     .as_ref()
163                     .map(|s| &s.tessellation_evaluation_shader.0),
164                 self.geometry_shader.as_ref().map(|s| &s.0),
165                 self.fragment_shader.as_ref().map(|s| &s.0),
166             ])
167             .flatten()
168             .collect();
169 
170             for (output, input) in stages.iter().zip(stages.iter().skip(1)) {
171                 if let Err(err) = input.input().matches(output.output()) {
172                     return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err));
173                 }
174             }
175 
176             let mut descriptor_set_layout_descs = stages
177                 .iter()
178                 .try_fold(vec![], |total, shader| -> Result<_, ()> {
179                     DescriptorSetDesc::union_multiple(&total, shader.descriptor_set_layout_descs())
180                 })
181                 .expect("Can't be union'd");
182             DescriptorSetDesc::tweak_multiple(
183                 &mut descriptor_set_layout_descs,
184                 dynamic_buffers.into_iter().cloned(),
185             );
186 
187             // We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
188             // e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
189             // Vertex and a subrange available to Fragment, like [0, 8)
190             let mut range_map = HashMap::new();
191             for stage in stages.iter() {
192                 if let Some(range) = stage.push_constant_range() {
193                     match range_map.entry((range.offset, range.size)) {
194                         Entry::Vacant(entry) => {
195                             entry.insert(range.stages);
196                         },
197                         Entry::Occupied(mut entry) => {
198                             *entry.get_mut() = *entry.get() | range.stages;
199                         },
200                     }
201                 }
202             }
203             let push_constant_ranges: Vec<_> = range_map
204                 .iter()
205                 .map(|((offset, size), stages)| {
206                     PipelineLayoutPcRange { offset: *offset, size: *size, stages: *stages }
207                 })
208                 .collect();
209 
210             (descriptor_set_layout_descs, push_constant_ranges)
211         };
212 
213         let descriptor_set_layouts = descriptor_set_layout_descs
214             .into_iter()
215             .map(|desc| Ok(Arc::new(DescriptorSetLayout::new(device.clone(), desc)?)))
216             .collect::<Result<Vec<_>, OomError>>()?;
217         let pipeline_layout = Arc::new(
218             PipelineLayout::new(device.clone(), descriptor_set_layouts, push_constant_ranges)
219                 .unwrap(),
220         );
221         self.with_pipeline_layout(device, pipeline_layout)
222     }
223 
224     /// Builds the graphics pipeline.
225     ///
226     /// Does the same as `build`, except that `build` automatically builds the pipeline layout
227     /// object corresponding to the union of your shaders while this function allows you to specify
228     /// the pipeline layout.
with_pipeline_layout( mut self, device: Arc<Device>, pipeline_layout: Arc<PipelineLayout>, ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError>229     pub fn with_pipeline_layout(
230         mut self,
231         device: Arc<Device>,
232         pipeline_layout: Arc<PipelineLayout>,
233     ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
234         // TODO: return errors instead of panicking if missing param
235 
236         let fns = device.fns();
237 
238         // Checking that the pipeline layout matches the shader stages.
239         // TODO: more details in the errors
240 
241         {
242             let shader = &self.vertex_shader.as_ref().unwrap().0;
243             pipeline_layout.ensure_superset_of(
244                 shader.descriptor_set_layout_descs(),
245                 shader.push_constant_range(),
246             )?;
247         }
248 
249         if let Some(ref geometry_shader) = self.geometry_shader {
250             let shader = &geometry_shader.0;
251             pipeline_layout.ensure_superset_of(
252                 shader.descriptor_set_layout_descs(),
253                 shader.push_constant_range(),
254             )?;
255         }
256 
257         if let Some(ref tess) = self.tessellation {
258             {
259                 let shader = &tess.tessellation_control_shader.0;
260                 pipeline_layout.ensure_superset_of(
261                     shader.descriptor_set_layout_descs(),
262                     shader.push_constant_range(),
263                 )?;
264             }
265 
266             {
267                 let shader = &tess.tessellation_evaluation_shader.0;
268                 pipeline_layout.ensure_superset_of(
269                     shader.descriptor_set_layout_descs(),
270                     shader.push_constant_range(),
271                 )?;
272             }
273         }
274 
275         if let Some(ref fragment_shader) = self.fragment_shader {
276             let shader = &fragment_shader.0;
277             pipeline_layout.ensure_superset_of(
278                 shader.descriptor_set_layout_descs(),
279                 shader.push_constant_range(),
280             )?;
281 
282             // Check that the subpass can accept the output of the fragment shader.
283             // TODO: If there is no fragment shader, what should be checked then? The previous stage?
284             if !self
285                 .subpass
286                 .as_ref()
287                 .unwrap()
288                 .is_compatible_with(shader.output())
289             {
290                 return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
291             }
292         }
293 
294         // Will contain the list of dynamic states. Filled throughout this function.
295         let mut dynamic_states: SmallVec<[ash::vk::DynamicState; 8]> = SmallVec::new();
296 
297         // Creating the specialization constants of the various stages.
298         let vertex_shader_specialization = {
299             let shader = self.vertex_shader.as_ref().unwrap();
300             let spec_descriptors = Vss::descriptors();
301             if spec_descriptors != shader.0.spec_constants() {
302                 return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
303             }
304 
305             let constants = &shader.1;
306             ash::vk::SpecializationInfo {
307                 map_entry_count: spec_descriptors.len() as u32,
308                 p_map_entries: spec_descriptors.as_ptr() as *const _,
309                 data_size: mem::size_of_val(constants),
310                 p_data: constants as *const Vss as *const _,
311             }
312         };
313 
314         let tess_shader_specialization = if let Some(ref tess) = self.tessellation {
315             let tcs_spec = {
316                 let shader = &tess.tessellation_control_shader;
317                 let spec_descriptors = Tcss::descriptors();
318                 if spec_descriptors != shader.0.spec_constants() {
319                     return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
320                 }
321 
322                 let constants = &shader.1;
323                 ash::vk::SpecializationInfo {
324                     map_entry_count: spec_descriptors.len() as u32,
325                     p_map_entries: spec_descriptors.as_ptr() as *const _,
326                     data_size: mem::size_of_val(constants),
327                     p_data: constants as *const Tcss as *const _,
328                 }
329             };
330             let tes_spec = {
331                 let shader = &tess.tessellation_evaluation_shader;
332                 let spec_descriptors = Tess::descriptors();
333                 if spec_descriptors != shader.0.spec_constants() {
334                     return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
335                 }
336 
337                 let constants = &shader.1;
338                 ash::vk::SpecializationInfo {
339                     map_entry_count: spec_descriptors.len() as u32,
340                     p_map_entries: spec_descriptors.as_ptr() as *const _,
341                     data_size: mem::size_of_val(constants),
342                     p_data: constants as *const Tess as *const _,
343                 }
344             };
345             Some((tcs_spec, tes_spec))
346         } else {
347             None
348         };
349 
350         let geometry_shader_specialization = if let Some(ref shader) = self.geometry_shader {
351             let spec_descriptors = Gss::descriptors();
352             if spec_descriptors != shader.0.spec_constants() {
353                 return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
354             }
355 
356             let constants = &shader.1;
357             Some(ash::vk::SpecializationInfo {
358                 map_entry_count: spec_descriptors.len() as u32,
359                 p_map_entries: spec_descriptors.as_ptr() as *const _,
360                 data_size: mem::size_of_val(constants),
361                 p_data: constants as *const Gss as *const _,
362             })
363         } else {
364             None
365         };
366 
367         let fragment_shader_specialization = if let Some(ref shader) = self.fragment_shader {
368             let spec_descriptors = Fss::descriptors();
369             if spec_descriptors != shader.0.spec_constants() {
370                 return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
371             }
372 
373             let constants = &shader.1;
374             Some(ash::vk::SpecializationInfo {
375                 map_entry_count: spec_descriptors.len() as u32,
376                 p_map_entries: spec_descriptors.as_ptr() as *const _,
377                 data_size: mem::size_of_val(constants),
378                 p_data: constants as *const Fss as *const _,
379             })
380         } else {
381             None
382         };
383 
384         // List of shader stages.
385         let stages = {
386             let mut stages = SmallVec::<[_; 5]>::new();
387 
388             match self.vertex_shader.as_ref().unwrap().0.ty() {
389                 GraphicsShaderType::Vertex => {}
390                 _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
391             };
392 
393             stages.push(ash::vk::PipelineShaderStageCreateInfo {
394                 flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
395                 stage: ash::vk::ShaderStageFlags::VERTEX,
396                 module: self
397                     .vertex_shader
398                     .as_ref()
399                     .unwrap()
400                     .0
401                     .module()
402                     .internal_object(),
403                 p_name: self.vertex_shader.as_ref().unwrap().0.name().as_ptr(),
404                 p_specialization_info: &vertex_shader_specialization as *const _,
405                 ..Default::default()
406             });
407 
408             if let Some(ref tess) = self.tessellation {
409                 // FIXME: must check that the control shader and evaluation shader are compatible
410 
411                 if !device.enabled_features().tessellation_shader {
412                     return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled);
413                 }
414 
415                 match tess.tessellation_control_shader.0.ty() {
416                     GraphicsShaderType::TessellationControl => {}
417                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
418                 };
419 
420                 match tess.tessellation_evaluation_shader.0.ty() {
421                     GraphicsShaderType::TessellationEvaluation => {}
422                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
423                 };
424 
425                 stages.push(ash::vk::PipelineShaderStageCreateInfo {
426                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
427                     stage: ash::vk::ShaderStageFlags::TESSELLATION_CONTROL,
428                     module: tess
429                         .tessellation_control_shader
430                         .0
431                         .module()
432                         .internal_object(),
433                     p_name: tess.tessellation_control_shader.0.name().as_ptr(),
434                     p_specialization_info: &tess_shader_specialization.as_ref().unwrap().0
435                         as *const _,
436                     ..Default::default()
437                 });
438 
439                 stages.push(ash::vk::PipelineShaderStageCreateInfo {
440                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
441                     stage: ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION,
442                     module: tess
443                         .tessellation_evaluation_shader
444                         .0
445                         .module()
446                         .internal_object(),
447                     p_name: tess.tessellation_evaluation_shader.0.name().as_ptr(),
448                     p_specialization_info: &tess_shader_specialization.as_ref().unwrap().1
449                         as *const _,
450                     ..Default::default()
451                 });
452             }
453 
454             if let Some(ref geometry_shader) = self.geometry_shader {
455                 if !device.enabled_features().geometry_shader {
456                     return Err(GraphicsPipelineCreationError::GeometryShaderFeatureNotEnabled);
457                 }
458 
459                 match geometry_shader.0.ty() {
460                     GraphicsShaderType::Geometry(_) => {}
461                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
462                 };
463 
464                 stages.push(ash::vk::PipelineShaderStageCreateInfo {
465                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
466                     stage: ash::vk::ShaderStageFlags::GEOMETRY,
467                     module: geometry_shader.0.module().internal_object(),
468                     p_name: geometry_shader.0.name().as_ptr(),
469                     p_specialization_info: geometry_shader_specialization.as_ref().unwrap()
470                         as *const _,
471                     ..Default::default()
472                 });
473             }
474 
475             if let Some(ref fragment_shader) = self.fragment_shader {
476                 match fragment_shader.0.ty() {
477                     GraphicsShaderType::Fragment => {}
478                     _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
479                 };
480 
481                 stages.push(ash::vk::PipelineShaderStageCreateInfo {
482                     flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
483                     stage: ash::vk::ShaderStageFlags::FRAGMENT,
484                     module: fragment_shader.0.module().internal_object(),
485                     p_name: fragment_shader.0.name().as_ptr(),
486                     p_specialization_info: fragment_shader_specialization.as_ref().unwrap()
487                         as *const _,
488                     ..Default::default()
489                 });
490             }
491 
492             stages
493         };
494 
495         // Vertex input.
496         let vertex_input = self
497             .vertex_definition
498             .definition(self.vertex_shader.as_ref().unwrap().0.input())?;
499 
500         let (binding_descriptions, binding_divisor_descriptions) = {
501             let mut binding_descriptions = SmallVec::<[_; 8]>::new();
502             let mut binding_divisor_descriptions = SmallVec::<[_; 8]>::new();
503 
504             for (binding, binding_desc) in vertex_input.bindings() {
505                 if binding
506                     >= device
507                         .physical_device()
508                         .properties()
509                         .max_vertex_input_bindings
510                 {
511                     return Err(
512                         GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
513                             max: device
514                                 .physical_device()
515                                 .properties()
516                                 .max_vertex_input_bindings,
517                             obtained: binding,
518                         },
519                     );
520                 }
521 
522                 if binding_desc.stride
523                     > device
524                         .physical_device()
525                         .properties()
526                         .max_vertex_input_binding_stride
527                 {
528                     return Err(
529                         GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
530                             binding,
531                             max: device
532                                 .physical_device()
533                                 .properties()
534                                 .max_vertex_input_binding_stride,
535                             obtained: binding_desc.stride,
536                         },
537                     );
538                 }
539 
540                 binding_descriptions.push(ash::vk::VertexInputBindingDescription {
541                     binding,
542                     stride: binding_desc.stride,
543                     input_rate: binding_desc.input_rate.into(),
544                 });
545 
546                 if let VertexInputRate::Instance { divisor } = binding_desc.input_rate {
547                     if divisor != 1 {
548                         if !device
549                             .enabled_features()
550                             .vertex_attribute_instance_rate_divisor
551                         {
552                             return Err(GraphicsPipelineCreationError::VertexAttributeInstanceRateDivisorFeatureNotEnabled);
553                         }
554 
555                         if divisor == 0
556                             && !device
557                                 .enabled_features()
558                                 .vertex_attribute_instance_rate_zero_divisor
559                         {
560                             return Err(GraphicsPipelineCreationError::VertexAttributeInstanceRateZeroDivisorFeatureNotEnabled);
561                         }
562 
563                         if divisor
564                             > device
565                                 .physical_device()
566                                 .properties()
567                                 .max_vertex_attrib_divisor
568                                 .unwrap()
569                         {
570                             return Err(
571                                 GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded {
572                                     binding,
573                                     max: device
574                                         .physical_device()
575                                         .properties()
576                                         .max_vertex_attrib_divisor
577                                         .unwrap(),
578                                     obtained: divisor,
579                                 },
580                             );
581                         }
582 
583                         binding_divisor_descriptions.push(
584                             ash::vk::VertexInputBindingDivisorDescriptionEXT { binding, divisor },
585                         )
586                     }
587                 }
588             }
589 
590             if binding_descriptions.len()
591                 > device
592                     .physical_device()
593                     .properties()
594                     .max_vertex_input_bindings as usize
595             {
596                 return Err(
597                     GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
598                         max: device
599                             .physical_device()
600                             .properties()
601                             .max_vertex_input_bindings,
602                         obtained: binding_descriptions.len() as u32,
603                     },
604                 );
605             }
606 
607             (binding_descriptions, binding_divisor_descriptions)
608         };
609 
610         let attribute_descriptions = {
611             let mut attribute_descriptions = SmallVec::<[_; 8]>::new();
612 
613             for (location, attribute_desc) in vertex_input.attributes() {
614                 // TODO: check attribute format support
615 
616                 if attribute_desc.offset
617                     > device
618                         .physical_device()
619                         .properties()
620                         .max_vertex_input_attribute_offset
621                 {
622                     return Err(
623                         GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
624                             max: device
625                                 .physical_device()
626                                 .properties()
627                                 .max_vertex_input_attribute_offset,
628                             obtained: attribute_desc.offset,
629                         },
630                     );
631                 }
632 
633                 attribute_descriptions.push(ash::vk::VertexInputAttributeDescription {
634                     location,
635                     binding: attribute_desc.binding,
636                     format: attribute_desc.format.into(),
637                     offset: attribute_desc.offset,
638                 });
639             }
640 
641             if attribute_descriptions.len()
642                 > device
643                     .physical_device()
644                     .properties()
645                     .max_vertex_input_attributes as usize
646             {
647                 return Err(
648                     GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
649                         max: device
650                             .physical_device()
651                             .properties()
652                             .max_vertex_input_attributes,
653                         obtained: attribute_descriptions.len(),
654                     },
655                 );
656             }
657 
658             attribute_descriptions
659         };
660 
661         let vertex_input_divisor_state = if !binding_divisor_descriptions.is_empty() {
662             Some(ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT {
663                 vertex_binding_divisor_count: binding_divisor_descriptions.len() as u32,
664                 p_vertex_binding_divisors: binding_divisor_descriptions.as_ptr(),
665                 ..Default::default()
666             })
667         } else {
668             None
669         };
670 
671         let vertex_input_state = ash::vk::PipelineVertexInputStateCreateInfo {
672             p_next: if let Some(next) = vertex_input_divisor_state.as_ref() {
673                 next as *const _ as *const _
674             } else {
675                 ptr::null()
676             },
677             flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(),
678             vertex_binding_description_count: binding_descriptions.len() as u32,
679             p_vertex_binding_descriptions: binding_descriptions.as_ptr(),
680             vertex_attribute_description_count: attribute_descriptions.len() as u32,
681             p_vertex_attribute_descriptions: attribute_descriptions.as_ptr(),
682             ..Default::default()
683         };
684 
685         if self.input_assembly.primitive_restart_enable != ash::vk::FALSE
686             && !self.input_assembly_topology.supports_primitive_restart()
687         {
688             return Err(
689                 GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart {
690                     primitive: self.input_assembly_topology,
691                 },
692             );
693         }
694 
695         // TODO: should check from the tess eval shader instead of the input assembly
696         if let Some(ref gs) = self.geometry_shader {
697             match gs.0.ty() {
698                 GraphicsShaderType::Geometry(primitives) => {
699                     if !primitives.matches(self.input_assembly_topology) {
700                         return Err(
701                             GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader,
702                         );
703                     }
704                 }
705                 _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
706             }
707         }
708 
709         let tessellation = match self.input_assembly_topology {
710             PrimitiveTopology::PatchList { vertices_per_patch } => {
711                 if self.tessellation.is_none() {
712                     return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
713                 }
714                 if vertices_per_patch
715                     > device
716                         .physical_device()
717                         .properties()
718                         .max_tessellation_patch_size
719                 {
720                     return Err(GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded);
721                 }
722 
723                 Some(ash::vk::PipelineTessellationStateCreateInfo {
724                     flags: ash::vk::PipelineTessellationStateCreateFlags::empty(),
725                     patch_control_points: vertices_per_patch,
726                     ..Default::default()
727                 })
728             }
729             _ => {
730                 if self.tessellation.is_some() {
731                     return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
732                 }
733 
734                 None
735             }
736         };
737 
738         let (vp_vp, vp_sc, vp_num) = match *self.viewport.as_ref().unwrap() {
739             ViewportsState::Fixed { ref data } => (
740                 data.iter()
741                     .map(|e| e.0.clone().into())
742                     .collect::<SmallVec<[ash::vk::Viewport; 4]>>(),
743                 data.iter()
744                     .map(|e| e.1.clone().into())
745                     .collect::<SmallVec<[ash::vk::Rect2D; 4]>>(),
746                 data.len() as u32,
747             ),
748             ViewportsState::DynamicViewports { ref scissors } => {
749                 let num = scissors.len() as u32;
750                 let scissors = scissors
751                     .iter()
752                     .map(|e| e.clone().into())
753                     .collect::<SmallVec<[ash::vk::Rect2D; 4]>>();
754                 dynamic_states.push(ash::vk::DynamicState::VIEWPORT);
755                 (SmallVec::new(), scissors, num)
756             }
757             ViewportsState::DynamicScissors { ref viewports } => {
758                 let num = viewports.len() as u32;
759                 let viewports = viewports
760                     .iter()
761                     .map(|e| e.clone().into())
762                     .collect::<SmallVec<[ash::vk::Viewport; 4]>>();
763                 dynamic_states.push(ash::vk::DynamicState::SCISSOR);
764                 (viewports, SmallVec::new(), num)
765             }
766             ViewportsState::Dynamic { num } => {
767                 dynamic_states.push(ash::vk::DynamicState::VIEWPORT);
768                 dynamic_states.push(ash::vk::DynamicState::SCISSOR);
769                 (SmallVec::new(), SmallVec::new(), num)
770             }
771         };
772 
773         if vp_num > 1 && !device.enabled_features().multi_viewport {
774             return Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled);
775         }
776 
777         if vp_num > device.physical_device().properties().max_viewports {
778             return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
779                 obtained: vp_num,
780                 max: device.physical_device().properties().max_viewports,
781             });
782         }
783 
784         for vp in vp_vp.iter() {
785             if vp.width
786                 > device
787                     .physical_device()
788                     .properties()
789                     .max_viewport_dimensions[0] as f32
790                 || vp.height
791                     > device
792                         .physical_device()
793                         .properties()
794                         .max_viewport_dimensions[1] as f32
795             {
796                 return Err(GraphicsPipelineCreationError::MaxViewportDimensionsExceeded);
797             }
798 
799             if vp.x
800                 < device
801                     .physical_device()
802                     .properties()
803                     .viewport_bounds_range[0]
804                 || vp.x + vp.width
805                     > device
806                         .physical_device()
807                         .properties()
808                         .viewport_bounds_range[1]
809                 || vp.y
810                     < device
811                         .physical_device()
812                         .properties()
813                         .viewport_bounds_range[0]
814                 || vp.y + vp.height
815                     > device
816                         .physical_device()
817                         .properties()
818                         .viewport_bounds_range[1]
819             {
820                 return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
821             }
822         }
823 
824         let viewport_info = ash::vk::PipelineViewportStateCreateInfo {
825             flags: ash::vk::PipelineViewportStateCreateFlags::empty(),
826             viewport_count: vp_num,
827             p_viewports: if vp_vp.is_empty() {
828                 ptr::null()
829             } else {
830                 vp_vp.as_ptr()
831             }, // validation layer crashes if you just pass the pointer
832             scissor_count: vp_num,
833             p_scissors: if vp_sc.is_empty() {
834                 ptr::null()
835             } else {
836                 vp_sc.as_ptr()
837             }, // validation layer crashes if you just pass the pointer
838             ..Default::default()
839         };
840 
841         if let Some(line_width) = self.raster.line_width {
842             if line_width != 1.0 && !device.enabled_features().wide_lines {
843                 return Err(GraphicsPipelineCreationError::WideLinesFeatureNotEnabled);
844             }
845         } else {
846             dynamic_states.push(ash::vk::DynamicState::LINE_WIDTH);
847         }
848 
849         let (db_enable, db_const, db_clamp, db_slope) = match self.raster.depth_bias {
850             DepthBiasControl::Dynamic => {
851                 dynamic_states.push(ash::vk::DynamicState::DEPTH_BIAS);
852                 (ash::vk::TRUE, 0.0, 0.0, 0.0)
853             }
854             DepthBiasControl::Disabled => (ash::vk::FALSE, 0.0, 0.0, 0.0),
855             DepthBiasControl::Static(bias) => {
856                 if bias.clamp != 0.0 && !device.enabled_features().depth_bias_clamp {
857                     return Err(GraphicsPipelineCreationError::DepthBiasClampFeatureNotEnabled);
858                 }
859 
860                 (
861                     ash::vk::TRUE,
862                     bias.constant_factor,
863                     bias.clamp,
864                     bias.slope_factor,
865                 )
866             }
867         };
868 
869         if self.raster.depth_clamp && !device.enabled_features().depth_clamp {
870             return Err(GraphicsPipelineCreationError::DepthClampFeatureNotEnabled);
871         }
872 
873         if self.raster.polygon_mode != PolygonMode::Fill
874             && !device.enabled_features().fill_mode_non_solid
875         {
876             return Err(GraphicsPipelineCreationError::FillModeNonSolidFeatureNotEnabled);
877         }
878 
879         let rasterization = ash::vk::PipelineRasterizationStateCreateInfo {
880             flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(),
881             depth_clamp_enable: if self.raster.depth_clamp {
882                 ash::vk::TRUE
883             } else {
884                 ash::vk::FALSE
885             },
886             rasterizer_discard_enable: if self.raster.rasterizer_discard {
887                 ash::vk::TRUE
888             } else {
889                 ash::vk::FALSE
890             },
891             polygon_mode: self.raster.polygon_mode.into(),
892             cull_mode: self.raster.cull_mode.into(),
893             front_face: self.raster.front_face.into(),
894             depth_bias_enable: db_enable,
895             depth_bias_constant_factor: db_const,
896             depth_bias_clamp: db_clamp,
897             depth_bias_slope_factor: db_slope,
898             line_width: self.raster.line_width.unwrap_or(1.0),
899             ..Default::default()
900         };
901 
902         self.multisample.rasterization_samples = self
903             .subpass
904             .as_ref()
905             .unwrap()
906             .num_samples()
907             .unwrap_or(SampleCount::Sample1)
908             .into();
909         if self.multisample.sample_shading_enable != ash::vk::FALSE {
910             debug_assert!(
911                 self.multisample.min_sample_shading >= 0.0
912                     && self.multisample.min_sample_shading <= 1.0
913             );
914             if !device.enabled_features().sample_rate_shading {
915                 return Err(GraphicsPipelineCreationError::SampleRateShadingFeatureNotEnabled);
916             }
917         }
918         if self.multisample.alpha_to_one_enable != ash::vk::FALSE {
919             if !device.enabled_features().alpha_to_one {
920                 return Err(GraphicsPipelineCreationError::AlphaToOneFeatureNotEnabled);
921             }
922         }
923 
924         let depth_stencil = {
925             let db = match self.depth_stencil.depth_bounds_test {
926                 DepthBounds::Disabled => (ash::vk::FALSE, 0.0, 0.0),
927                 DepthBounds::Fixed(ref range) => {
928                     if !device.enabled_features().depth_bounds {
929                         return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
930                     }
931 
932                     (ash::vk::TRUE, range.start, range.end)
933                 }
934                 DepthBounds::Dynamic => {
935                     if !device.enabled_features().depth_bounds {
936                         return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
937                     }
938 
939                     dynamic_states.push(ash::vk::DynamicState::DEPTH_BOUNDS);
940 
941                     (ash::vk::TRUE, 0.0, 1.0)
942                 }
943             };
944 
945             match (
946                 self.depth_stencil.stencil_front.compare_mask,
947                 self.depth_stencil.stencil_back.compare_mask,
948             ) {
949                 (Some(_), Some(_)) => (),
950                 (None, None) => {
951                     dynamic_states.push(ash::vk::DynamicState::STENCIL_COMPARE_MASK);
952                 }
953                 _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
954             };
955 
956             match (
957                 self.depth_stencil.stencil_front.write_mask,
958                 self.depth_stencil.stencil_back.write_mask,
959             ) {
960                 (Some(_), Some(_)) => (),
961                 (None, None) => {
962                     dynamic_states.push(ash::vk::DynamicState::STENCIL_WRITE_MASK);
963                 }
964                 _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
965             };
966 
967             match (
968                 self.depth_stencil.stencil_front.reference,
969                 self.depth_stencil.stencil_back.reference,
970             ) {
971                 (Some(_), Some(_)) => (),
972                 (None, None) => {
973                     dynamic_states.push(ash::vk::DynamicState::STENCIL_REFERENCE);
974                 }
975                 _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
976             };
977 
978             if self.depth_stencil.depth_write
979                 && !self.subpass.as_ref().unwrap().has_writable_depth()
980             {
981                 return Err(GraphicsPipelineCreationError::NoDepthAttachment);
982             }
983 
984             if self.depth_stencil.depth_compare != Compare::Always
985                 && !self.subpass.as_ref().unwrap().has_depth()
986             {
987                 return Err(GraphicsPipelineCreationError::NoDepthAttachment);
988             }
989 
990             if (!self.depth_stencil.stencil_front.always_keep()
991                 || !self.depth_stencil.stencil_back.always_keep())
992                 && !self.subpass.as_ref().unwrap().has_stencil()
993             {
994                 return Err(GraphicsPipelineCreationError::NoStencilAttachment);
995             }
996 
997             // FIXME: stencil writability
998 
999             ash::vk::PipelineDepthStencilStateCreateInfo {
1000                 flags: ash::vk::PipelineDepthStencilStateCreateFlags::empty(),
1001                 depth_test_enable: if !self.depth_stencil.depth_write
1002                     && self.depth_stencil.depth_compare == Compare::Always
1003                 {
1004                     ash::vk::FALSE
1005                 } else {
1006                     ash::vk::TRUE
1007                 },
1008                 depth_write_enable: if self.depth_stencil.depth_write {
1009                     ash::vk::TRUE
1010                 } else {
1011                     ash::vk::FALSE
1012                 },
1013                 depth_compare_op: self.depth_stencil.depth_compare.into(),
1014                 depth_bounds_test_enable: db.0,
1015                 stencil_test_enable: if self.depth_stencil.stencil_front.always_keep()
1016                     && self.depth_stencil.stencil_back.always_keep()
1017                 {
1018                     ash::vk::FALSE
1019                 } else {
1020                     ash::vk::TRUE
1021                 },
1022                 front: ash::vk::StencilOpState {
1023                     fail_op: self.depth_stencil.stencil_front.fail_op.into(),
1024                     pass_op: self.depth_stencil.stencil_front.pass_op.into(),
1025                     depth_fail_op: self.depth_stencil.stencil_front.depth_fail_op.into(),
1026                     compare_op: self.depth_stencil.stencil_front.compare.into(),
1027                     compare_mask: self
1028                         .depth_stencil
1029                         .stencil_front
1030                         .compare_mask
1031                         .unwrap_or(u32::MAX),
1032                     write_mask: self
1033                         .depth_stencil
1034                         .stencil_front
1035                         .write_mask
1036                         .unwrap_or(u32::MAX),
1037                     reference: self.depth_stencil.stencil_front.reference.unwrap_or(0),
1038                 },
1039                 back: ash::vk::StencilOpState {
1040                     fail_op: self.depth_stencil.stencil_back.fail_op.into(),
1041                     pass_op: self.depth_stencil.stencil_back.pass_op.into(),
1042                     depth_fail_op: self.depth_stencil.stencil_back.depth_fail_op.into(),
1043                     compare_op: self.depth_stencil.stencil_back.compare.into(),
1044                     compare_mask: self
1045                         .depth_stencil
1046                         .stencil_back
1047                         .compare_mask
1048                         .unwrap_or(u32::MAX),
1049                     write_mask: self
1050                         .depth_stencil
1051                         .stencil_back
1052                         .write_mask
1053                         .unwrap_or(u32::MAX),
1054                     reference: self.depth_stencil.stencil_back.reference.unwrap_or(0),
1055                 },
1056                 min_depth_bounds: db.1,
1057                 max_depth_bounds: db.2,
1058                 ..Default::default()
1059             }
1060         };
1061 
1062         let blend_atch: SmallVec<[ash::vk::PipelineColorBlendAttachmentState; 8]> = {
1063             let num_atch = self.subpass.as_ref().unwrap().num_color_attachments();
1064 
1065             match self.blend.attachments {
1066                 AttachmentsBlend::Collective(blend) => {
1067                     (0..num_atch).map(|_| blend.clone().into()).collect()
1068                 }
1069                 AttachmentsBlend::Individual(blend) => {
1070                     if blend.len() != num_atch as usize {
1071                         return Err(
1072                             GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount,
1073                         );
1074                     }
1075 
1076                     if !device.enabled_features().independent_blend {
1077                         return Err(
1078                             GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled,
1079                         );
1080                     }
1081 
1082                     blend.iter().map(|b| b.clone().into()).collect()
1083                 }
1084             }
1085         };
1086 
1087         let blend = ash::vk::PipelineColorBlendStateCreateInfo {
1088             flags: ash::vk::PipelineColorBlendStateCreateFlags::empty(),
1089             logic_op_enable: if self.blend.logic_op.is_some() {
1090                 if !device.enabled_features().logic_op {
1091                     return Err(GraphicsPipelineCreationError::LogicOpFeatureNotEnabled);
1092                 }
1093                 ash::vk::TRUE
1094             } else {
1095                 ash::vk::FALSE
1096             },
1097             logic_op: self.blend.logic_op.unwrap_or(Default::default()).into(),
1098             attachment_count: blend_atch.len() as u32,
1099             p_attachments: blend_atch.as_ptr(),
1100             blend_constants: if let Some(c) = self.blend.blend_constants {
1101                 c
1102             } else {
1103                 dynamic_states.push(ash::vk::DynamicState::BLEND_CONSTANTS);
1104                 [0.0, 0.0, 0.0, 0.0]
1105             },
1106             ..Default::default()
1107         };
1108 
1109         let dynamic_states = if !dynamic_states.is_empty() {
1110             Some(ash::vk::PipelineDynamicStateCreateInfo {
1111                 flags: ash::vk::PipelineDynamicStateCreateFlags::empty(),
1112                 dynamic_state_count: dynamic_states.len() as u32,
1113                 p_dynamic_states: dynamic_states.as_ptr(),
1114                 ..Default::default()
1115             })
1116         } else {
1117             None
1118         };
1119 
1120         if let Some(multiview) = self
1121             .subpass
1122             .as_ref()
1123             .unwrap()
1124             .render_pass()
1125             .desc()
1126             .multiview()
1127             .as_ref()
1128         {
1129             if multiview.used_layer_count() > 0 {
1130                 if self.geometry_shader.is_some()
1131                     && !device
1132                         .physical_device()
1133                         .supported_features()
1134                         .multiview_geometry_shader
1135                 {
1136                     return Err(GraphicsPipelineCreationError::MultiviewGeometryShaderNotSupported);
1137                 }
1138 
1139                 if self.tessellation.is_some()
1140                     && !device
1141                         .physical_device()
1142                         .supported_features()
1143                         .multiview_tessellation_shader
1144                 {
1145                     return Err(
1146                         GraphicsPipelineCreationError::MultiviewTessellationShaderNotSupported,
1147                     );
1148                 }
1149             }
1150         }
1151 
1152         let pipeline = unsafe {
1153             let infos = ash::vk::GraphicsPipelineCreateInfo {
1154                 flags: ash::vk::PipelineCreateFlags::empty(), // TODO: some flags are available but none are critical
1155                 stage_count: stages.len() as u32,
1156                 p_stages: stages.as_ptr(),
1157                 p_vertex_input_state: &vertex_input_state,
1158                 p_input_assembly_state: &self.input_assembly,
1159                 p_tessellation_state: tessellation
1160                     .as_ref()
1161                     .map(|t| t as *const _)
1162                     .unwrap_or(ptr::null()),
1163                 p_viewport_state: &viewport_info,
1164                 p_rasterization_state: &rasterization,
1165                 p_multisample_state: &self.multisample,
1166                 p_depth_stencil_state: &depth_stencil,
1167                 p_color_blend_state: &blend,
1168                 p_dynamic_state: dynamic_states
1169                     .as_ref()
1170                     .map(|s| s as *const _)
1171                     .unwrap_or(ptr::null()),
1172                 layout: pipeline_layout.internal_object(),
1173                 render_pass: self
1174                     .subpass
1175                     .as_ref()
1176                     .unwrap()
1177                     .render_pass()
1178                     .inner()
1179                     .internal_object(),
1180                 subpass: self.subpass.as_ref().unwrap().index(),
1181                 base_pipeline_handle: ash::vk::Pipeline::null(), // TODO:
1182                 base_pipeline_index: -1,                         // TODO:
1183                 ..Default::default()
1184             };
1185 
1186             let cache_handle = match self.cache {
1187                 Some(cache) => cache.internal_object(),
1188                 None => ash::vk::PipelineCache::null(),
1189             };
1190 
1191             let mut output = MaybeUninit::uninit();
1192             check_errors(fns.v1_0.create_graphics_pipelines(
1193                 device.internal_object(),
1194                 cache_handle,
1195                 1,
1196                 &infos,
1197                 ptr::null(),
1198                 output.as_mut_ptr(),
1199             ))?;
1200             output.assume_init()
1201         };
1202 
1203         // Some drivers return `VK_SUCCESS` but provide a null handle if they
1204         // fail to create the pipeline (due to invalid shaders, etc)
1205         // This check ensures that we don't create an invalid `GraphicsPipeline` instance
1206         if pipeline == ash::vk::Pipeline::null() {
1207             panic!("vkCreateGraphicsPipelines provided a NULL handle");
1208         }
1209 
1210         Ok(GraphicsPipeline {
1211             inner: GraphicsPipelineInner {
1212                 device: device.clone(),
1213                 pipeline,
1214             },
1215             layout: pipeline_layout,
1216             subpass: self.subpass.take().unwrap(),
1217             vertex_definition: self.vertex_definition,
1218             vertex_input,
1219 
1220             dynamic_line_width: self.raster.line_width.is_none(),
1221             dynamic_viewport: self.viewport.as_ref().unwrap().dynamic_viewports(),
1222             dynamic_scissor: self.viewport.as_ref().unwrap().dynamic_scissors(),
1223             dynamic_depth_bias: self.raster.depth_bias.is_dynamic(),
1224             dynamic_depth_bounds: self.depth_stencil.depth_bounds_test.is_dynamic(),
1225             dynamic_stencil_compare_mask: self.depth_stencil.stencil_back.compare_mask.is_none(),
1226             dynamic_stencil_write_mask: self.depth_stencil.stencil_back.write_mask.is_none(),
1227             dynamic_stencil_reference: self.depth_stencil.stencil_back.reference.is_none(),
1228             dynamic_blend_constants: self.blend.blend_constants.is_none(),
1229 
1230             num_viewports: self.viewport.as_ref().unwrap().num_viewports(),
1231         })
1232     }
1233 
1234     // TODO: add build_with_cache method
1235 }
1236 
1237 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
1238     GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
1239 {
1240     // TODO: add pipeline derivate system
1241 
1242     /// Sets the vertex input.
1243     #[inline]
vertex_input<T>( self, vertex_definition: T, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss>1244     pub fn vertex_input<T>(
1245         self,
1246         vertex_definition: T,
1247     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss> {
1248         GraphicsPipelineBuilder {
1249             vertex_definition,
1250             vertex_shader: self.vertex_shader,
1251             input_assembly: self.input_assembly,
1252             input_assembly_topology: self.input_assembly_topology,
1253             tessellation: self.tessellation,
1254             geometry_shader: self.geometry_shader,
1255             viewport: self.viewport,
1256             raster: self.raster,
1257             multisample: self.multisample,
1258             fragment_shader: self.fragment_shader,
1259             depth_stencil: self.depth_stencil,
1260             blend: self.blend,
1261             subpass: self.subpass,
1262             cache: self.cache,
1263         }
1264     }
1265 
1266     /// Sets the vertex input to a single vertex buffer.
1267     ///
1268     /// You will most likely need to explicitly specify the template parameter to the type of a
1269     /// vertex.
1270     #[inline]
vertex_input_single_buffer<V: Vertex>( self, ) -> GraphicsPipelineBuilder< 'vs, 'tcs, 'tes, 'gs, 'fs, BuffersDefinition, Vss, Tcss, Tess, Gss, Fss, >1271     pub fn vertex_input_single_buffer<V: Vertex>(
1272         self,
1273     ) -> GraphicsPipelineBuilder<
1274         'vs,
1275         'tcs,
1276         'tes,
1277         'gs,
1278         'fs,
1279         BuffersDefinition,
1280         Vss,
1281         Tcss,
1282         Tess,
1283         Gss,
1284         Fss,
1285     > {
1286         self.vertex_input(BuffersDefinition::new().vertex::<V>())
1287     }
1288 
1289     /// Sets the vertex shader to use.
1290     // TODO: correct specialization constants
1291     #[inline]
vertex_shader<'vs2, Vss2>( self, shader: GraphicsEntryPoint<'vs2>, specialization_constants: Vss2, ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss> where Vss2: SpecializationConstants,1292     pub fn vertex_shader<'vs2, Vss2>(
1293         self,
1294         shader: GraphicsEntryPoint<'vs2>,
1295         specialization_constants: Vss2,
1296     ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss>
1297     where
1298         Vss2: SpecializationConstants,
1299     {
1300         GraphicsPipelineBuilder {
1301             vertex_definition: self.vertex_definition,
1302             vertex_shader: Some((shader, specialization_constants)),
1303             input_assembly: self.input_assembly,
1304             input_assembly_topology: self.input_assembly_topology,
1305             tessellation: self.tessellation,
1306             geometry_shader: self.geometry_shader,
1307             viewport: self.viewport,
1308             raster: self.raster,
1309             multisample: self.multisample,
1310             fragment_shader: self.fragment_shader,
1311             depth_stencil: self.depth_stencil,
1312             blend: self.blend,
1313             subpass: self.subpass,
1314             cache: self.cache,
1315         }
1316     }
1317 
1318     /// Sets whether primitive restart if enabled.
1319     #[inline]
primitive_restart(mut self, enabled: bool) -> Self1320     pub fn primitive_restart(mut self, enabled: bool) -> Self {
1321         self.input_assembly.primitive_restart_enable = if enabled {
1322             ash::vk::TRUE
1323         } else {
1324             ash::vk::FALSE
1325         };
1326 
1327         self
1328     }
1329 
1330     /// Sets the topology of the primitives that are expected by the pipeline.
1331     #[inline]
primitive_topology(mut self, topology: PrimitiveTopology) -> Self1332     pub fn primitive_topology(mut self, topology: PrimitiveTopology) -> Self {
1333         self.input_assembly_topology = topology;
1334         self.input_assembly.topology = topology.into();
1335         self
1336     }
1337 
1338     /// Sets the topology of the primitives to a list of points.
1339     ///
1340     /// > **Note**: This is equivalent to
1341     /// > `self.primitive_topology(PrimitiveTopology::PointList)`.
1342     #[inline]
point_list(self) -> Self1343     pub fn point_list(self) -> Self {
1344         self.primitive_topology(PrimitiveTopology::PointList)
1345     }
1346 
1347     /// Sets the topology of the primitives to a list of lines.
1348     ///
1349     /// > **Note**: This is equivalent to
1350     /// > `self.primitive_topology(PrimitiveTopology::LineList)`.
1351     #[inline]
line_list(self) -> Self1352     pub fn line_list(self) -> Self {
1353         self.primitive_topology(PrimitiveTopology::LineList)
1354     }
1355 
1356     /// Sets the topology of the primitives to a line strip.
1357     ///
1358     /// > **Note**: This is equivalent to
1359     /// > `self.primitive_topology(PrimitiveTopology::LineStrip)`.
1360     #[inline]
line_strip(self) -> Self1361     pub fn line_strip(self) -> Self {
1362         self.primitive_topology(PrimitiveTopology::LineStrip)
1363     }
1364 
1365     /// Sets the topology of the primitives to a list of triangles. Note that this is the default.
1366     ///
1367     /// > **Note**: This is equivalent to
1368     /// > `self.primitive_topology(PrimitiveTopology::TriangleList)`.
1369     #[inline]
triangle_list(self) -> Self1370     pub fn triangle_list(self) -> Self {
1371         self.primitive_topology(PrimitiveTopology::TriangleList)
1372     }
1373 
1374     /// Sets the topology of the primitives to a triangle strip.
1375     ///
1376     /// > **Note**: This is equivalent to
1377     /// > `self.primitive_topology(PrimitiveTopology::TriangleStrip)`.
1378     #[inline]
triangle_strip(self) -> Self1379     pub fn triangle_strip(self) -> Self {
1380         self.primitive_topology(PrimitiveTopology::TriangleStrip)
1381     }
1382 
1383     /// Sets the topology of the primitives to a fan of triangles.
1384     ///
1385     /// > **Note**: This is equivalent to
1386     /// > `self.primitive_topology(PrimitiveTopology::TriangleFan)`.
1387     #[inline]
triangle_fan(self) -> Self1388     pub fn triangle_fan(self) -> Self {
1389         self.primitive_topology(PrimitiveTopology::TriangleFan)
1390     }
1391 
1392     /// Sets the topology of the primitives to a list of lines with adjacency information.
1393     ///
1394     /// > **Note**: This is equivalent to
1395     /// > `self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)`.
1396     #[inline]
line_list_with_adjacency(self) -> Self1397     pub fn line_list_with_adjacency(self) -> Self {
1398         self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)
1399     }
1400 
1401     /// Sets the topology of the primitives to a line strip with adjacency information.
1402     ///
1403     /// > **Note**: This is equivalent to
1404     /// > `self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)`.
1405     #[inline]
line_strip_with_adjacency(self) -> Self1406     pub fn line_strip_with_adjacency(self) -> Self {
1407         self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)
1408     }
1409 
1410     /// Sets the topology of the primitives to a list of triangles with adjacency information.
1411     ///
1412     /// > **Note**: This is equivalent to
1413     /// > `self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)`.
1414     #[inline]
triangle_list_with_adjacency(self) -> Self1415     pub fn triangle_list_with_adjacency(self) -> Self {
1416         self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)
1417     }
1418 
1419     /// Sets the topology of the primitives to a triangle strip with adjacency information`
1420     ///
1421     /// > **Note**: This is equivalent to
1422     /// > `self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)`.
1423     #[inline]
triangle_strip_with_adjacency(self) -> Self1424     pub fn triangle_strip_with_adjacency(self) -> Self {
1425         self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)
1426     }
1427 
1428     /// Sets the topology of the primitives to a list of patches. Can only be used and must be used
1429     /// with a tessellation shader.
1430     ///
1431     /// > **Note**: This is equivalent to
1432     /// > `self.primitive_topology(PrimitiveTopology::PatchList { vertices_per_patch })`.
1433     #[inline]
patch_list(self, vertices_per_patch: u32) -> Self1434     pub fn patch_list(self, vertices_per_patch: u32) -> Self {
1435         self.primitive_topology(PrimitiveTopology::PatchList { vertices_per_patch })
1436     }
1437 
1438     /// Sets the tessellation shaders to use.
1439     // TODO: correct specialization constants
1440     #[inline]
tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>( self, tessellation_control_shader: GraphicsEntryPoint<'tcs2>, tessellation_control_shader_spec_constants: Tcss2, tessellation_evaluation_shader: GraphicsEntryPoint<'tes2>, tessellation_evaluation_shader_spec_constants: Tess2, ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss> where Tcss2: SpecializationConstants, Tess2: SpecializationConstants,1441     pub fn tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>(
1442         self,
1443         tessellation_control_shader: GraphicsEntryPoint<'tcs2>,
1444         tessellation_control_shader_spec_constants: Tcss2,
1445         tessellation_evaluation_shader: GraphicsEntryPoint<'tes2>,
1446         tessellation_evaluation_shader_spec_constants: Tess2,
1447     ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss>
1448     where
1449         Tcss2: SpecializationConstants,
1450         Tess2: SpecializationConstants,
1451     {
1452         GraphicsPipelineBuilder {
1453             vertex_definition: self.vertex_definition,
1454             vertex_shader: self.vertex_shader,
1455             input_assembly: self.input_assembly,
1456             input_assembly_topology: self.input_assembly_topology,
1457             tessellation: Some(TessInfo {
1458                 tessellation_control_shader: (
1459                     tessellation_control_shader,
1460                     tessellation_control_shader_spec_constants,
1461                 ),
1462                 tessellation_evaluation_shader: (
1463                     tessellation_evaluation_shader,
1464                     tessellation_evaluation_shader_spec_constants,
1465                 ),
1466             }),
1467             geometry_shader: self.geometry_shader,
1468             viewport: self.viewport,
1469             raster: self.raster,
1470             multisample: self.multisample,
1471             fragment_shader: self.fragment_shader,
1472             depth_stencil: self.depth_stencil,
1473             blend: self.blend,
1474             subpass: self.subpass,
1475             cache: self.cache,
1476         }
1477     }
1478 
1479     /// Sets the tessellation shaders stage as disabled. This is the default.
1480     #[inline]
tessellation_shaders_disabled(mut self) -> Self1481     pub fn tessellation_shaders_disabled(mut self) -> Self {
1482         self.tessellation = None;
1483         self
1484     }
1485 
1486     /// Sets the geometry shader to use.
1487     // TODO: correct specialization constants
1488     #[inline]
geometry_shader<'gs2, Gss2>( self, shader: GraphicsEntryPoint<'gs2>, specialization_constants: Gss2, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss> where Gss2: SpecializationConstants,1489     pub fn geometry_shader<'gs2, Gss2>(
1490         self,
1491         shader: GraphicsEntryPoint<'gs2>,
1492         specialization_constants: Gss2,
1493     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss>
1494     where
1495         Gss2: SpecializationConstants,
1496     {
1497         GraphicsPipelineBuilder {
1498             vertex_definition: self.vertex_definition,
1499             vertex_shader: self.vertex_shader,
1500             input_assembly: self.input_assembly,
1501             input_assembly_topology: self.input_assembly_topology,
1502             tessellation: self.tessellation,
1503             geometry_shader: Some((shader, specialization_constants)),
1504             viewport: self.viewport,
1505             raster: self.raster,
1506             multisample: self.multisample,
1507             fragment_shader: self.fragment_shader,
1508             depth_stencil: self.depth_stencil,
1509             blend: self.blend,
1510             subpass: self.subpass,
1511             cache: self.cache,
1512         }
1513     }
1514 
1515     /// Sets the geometry shader stage as disabled. This is the default.
1516     #[inline]
geometry_shader_disabled(mut self) -> Self1517     pub fn geometry_shader_disabled(mut self) -> Self {
1518         self.geometry_shader = None;
1519         self
1520     }
1521 
1522     /// Sets the viewports to some value, and the scissor boxes to boxes that always cover the
1523     /// whole viewport.
1524     #[inline]
viewports<I>(self, viewports: I) -> Self where I: IntoIterator<Item = Viewport>,1525     pub fn viewports<I>(self, viewports: I) -> Self
1526     where
1527         I: IntoIterator<Item = Viewport>,
1528     {
1529         self.viewports_scissors(viewports.into_iter().map(|v| (v, Scissor::irrelevant())))
1530     }
1531 
1532     /// Sets the characteristics of viewports and scissor boxes in advance.
1533     #[inline]
viewports_scissors<I>(mut self, viewports: I) -> Self where I: IntoIterator<Item = (Viewport, Scissor)>,1534     pub fn viewports_scissors<I>(mut self, viewports: I) -> Self
1535     where
1536         I: IntoIterator<Item = (Viewport, Scissor)>,
1537     {
1538         self.viewport = Some(ViewportsState::Fixed {
1539             data: viewports.into_iter().collect(),
1540         });
1541         self
1542     }
1543 
1544     /// Sets the scissor boxes to some values, and viewports to dynamic. The viewports will
1545     /// need to be set before drawing.
1546     #[inline]
viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self where I: IntoIterator<Item = Scissor>,1547     pub fn viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self
1548     where
1549         I: IntoIterator<Item = Scissor>,
1550     {
1551         self.viewport = Some(ViewportsState::DynamicViewports {
1552             scissors: scissors.into_iter().collect(),
1553         });
1554         self
1555     }
1556 
1557     /// Sets the viewports to dynamic, and the scissor boxes to boxes that always cover the whole
1558     /// viewport. The viewports will need to be set before drawing.
1559     #[inline]
viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self1560     pub fn viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self {
1561         self.viewport = Some(ViewportsState::DynamicViewports {
1562             scissors: (0..num).map(|_| Scissor::irrelevant()).collect(),
1563         });
1564         self
1565     }
1566 
1567     /// Sets the viewports to some values, and scissor boxes to dynamic. The scissor boxes will
1568     /// need to be set before drawing.
1569     #[inline]
viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self where I: IntoIterator<Item = Viewport>,1570     pub fn viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self
1571     where
1572         I: IntoIterator<Item = Viewport>,
1573     {
1574         self.viewport = Some(ViewportsState::DynamicScissors {
1575             viewports: viewports.into_iter().collect(),
1576         });
1577         self
1578     }
1579 
1580     /// Sets the viewports and scissor boxes to dynamic. They will both need to be set before
1581     /// drawing.
1582     #[inline]
viewports_scissors_dynamic(mut self, num: u32) -> Self1583     pub fn viewports_scissors_dynamic(mut self, num: u32) -> Self {
1584         self.viewport = Some(ViewportsState::Dynamic { num });
1585         self
1586     }
1587 
1588     /// If true, then the depth value of the vertices will be clamped to the range `[0.0 ; 1.0]`.
1589     /// If false, fragments whose depth is outside of this range will be discarded before the
1590     /// fragment shader even runs.
1591     #[inline]
depth_clamp(mut self, clamp: bool) -> Self1592     pub fn depth_clamp(mut self, clamp: bool) -> Self {
1593         self.raster.depth_clamp = clamp;
1594         self
1595     }
1596 
1597     // TODO: this won't work correctly
1598     /*/// Disables the fragment shader stage.
1599     #[inline]
1600     pub fn rasterizer_discard(mut self) -> Self {
1601         self.rasterization.rasterizer_discard. = true;
1602         self
1603     }*/
1604 
1605     /// Sets the front-facing faces to counter-clockwise faces. This is the default.
1606     ///
1607     /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
1608     /// as facing their front. Otherwise they will be considered as facing their back.
1609     #[inline]
front_face_counter_clockwise(mut self) -> Self1610     pub fn front_face_counter_clockwise(mut self) -> Self {
1611         self.raster.front_face = FrontFace::CounterClockwise;
1612         self
1613     }
1614 
1615     /// Sets the front-facing faces to clockwise faces.
1616     ///
1617     /// Triangles whose vertices are oriented clockwise on the screen will be considered
1618     /// as facing their front. Otherwise they will be considered as facing their back.
1619     #[inline]
front_face_clockwise(mut self) -> Self1620     pub fn front_face_clockwise(mut self) -> Self {
1621         self.raster.front_face = FrontFace::Clockwise;
1622         self
1623     }
1624 
1625     /// Sets backface culling as disabled. This is the default.
1626     #[inline]
cull_mode_disabled(mut self) -> Self1627     pub fn cull_mode_disabled(mut self) -> Self {
1628         self.raster.cull_mode = CullMode::None;
1629         self
1630     }
1631 
1632     /// Sets backface culling to front faces. The front faces (as chosen with the `front_face_*`
1633     /// methods) will be discarded by the GPU when drawing.
1634     #[inline]
cull_mode_front(mut self) -> Self1635     pub fn cull_mode_front(mut self) -> Self {
1636         self.raster.cull_mode = CullMode::Front;
1637         self
1638     }
1639 
1640     /// Sets backface culling to back faces. Faces that are not facing the front (as chosen with
1641     /// the `front_face_*` methods) will be discarded by the GPU when drawing.
1642     #[inline]
cull_mode_back(mut self) -> Self1643     pub fn cull_mode_back(mut self) -> Self {
1644         self.raster.cull_mode = CullMode::Back;
1645         self
1646     }
1647 
1648     /// Sets backface culling to both front and back faces. All the faces will be discarded.
1649     ///
1650     /// > **Note**: This option exists for the sake of completeness. It has no known practical
1651     /// > usage.
1652     #[inline]
cull_mode_front_and_back(mut self) -> Self1653     pub fn cull_mode_front_and_back(mut self) -> Self {
1654         self.raster.cull_mode = CullMode::FrontAndBack;
1655         self
1656     }
1657 
1658     /// Sets the polygon mode to "fill". This is the default.
1659     #[inline]
polygon_mode_fill(mut self) -> Self1660     pub fn polygon_mode_fill(mut self) -> Self {
1661         self.raster.polygon_mode = PolygonMode::Fill;
1662         self
1663     }
1664 
1665     /// Sets the polygon mode to "line". Triangles will each be turned into three lines.
1666     #[inline]
polygon_mode_line(mut self) -> Self1667     pub fn polygon_mode_line(mut self) -> Self {
1668         self.raster.polygon_mode = PolygonMode::Line;
1669         self
1670     }
1671 
1672     /// Sets the polygon mode to "point". Triangles and lines will each be turned into three points.
1673     #[inline]
polygon_mode_point(mut self) -> Self1674     pub fn polygon_mode_point(mut self) -> Self {
1675         self.raster.polygon_mode = PolygonMode::Point;
1676         self
1677     }
1678 
1679     /// Sets the width of the lines, if the GPU needs to draw lines. The default is `1.0`.
1680     #[inline]
line_width(mut self, value: f32) -> Self1681     pub fn line_width(mut self, value: f32) -> Self {
1682         self.raster.line_width = Some(value);
1683         self
1684     }
1685 
1686     /// Sets the width of the lines as dynamic, which means that you will need to set this value
1687     /// when drawing.
1688     #[inline]
line_width_dynamic(mut self) -> Self1689     pub fn line_width_dynamic(mut self) -> Self {
1690         self.raster.line_width = None;
1691         self
1692     }
1693 
1694     // TODO: missing DepthBiasControl
1695 
1696     /// Disables sample shading. The fragment shader will only be run once per fragment (ie. per
1697     /// pixel) and not once by sample. The output will then be copied in all of the covered
1698     /// samples.
1699     ///
1700     /// Sample shading is disabled by default.
1701     #[inline]
sample_shading_disabled(mut self) -> Self1702     pub fn sample_shading_disabled(mut self) -> Self {
1703         self.multisample.sample_shading_enable = ash::vk::FALSE;
1704         self
1705     }
1706 
1707     /// Enables sample shading. The fragment shader will be run once per sample at the borders of
1708     /// the object you're drawing.
1709     ///
1710     /// Enabling sampling shading requires the `sample_rate_shading` feature to be enabled on the
1711     /// device.
1712     ///
1713     /// The `min_fract` parameter is the minimum fraction of samples shading. For example if its
1714     /// value is 0.5, then the fragment shader will run for at least half of the samples. The other
1715     /// half of the samples will get their values determined automatically.
1716     ///
1717     /// Sample shading is disabled by default.
1718     ///
1719     /// # Panic
1720     ///
1721     /// - Panics if `min_fract` is not between 0.0 and 1.0.
1722     ///
1723     #[inline]
sample_shading_enabled(mut self, min_fract: f32) -> Self1724     pub fn sample_shading_enabled(mut self, min_fract: f32) -> Self {
1725         assert!(min_fract >= 0.0 && min_fract <= 1.0);
1726         self.multisample.sample_shading_enable = ash::vk::TRUE;
1727         self.multisample.min_sample_shading = min_fract;
1728         self
1729     }
1730 
1731     // TODO: doc
alpha_to_coverage_disabled(mut self) -> Self1732     pub fn alpha_to_coverage_disabled(mut self) -> Self {
1733         self.multisample.alpha_to_coverage_enable = ash::vk::FALSE;
1734         self
1735     }
1736 
1737     // TODO: doc
alpha_to_coverage_enabled(mut self) -> Self1738     pub fn alpha_to_coverage_enabled(mut self) -> Self {
1739         self.multisample.alpha_to_coverage_enable = ash::vk::TRUE;
1740         self
1741     }
1742 
1743     /// Disables alpha-to-one.
1744     ///
1745     /// Alpha-to-one is disabled by default.
1746     #[inline]
alpha_to_one_disabled(mut self) -> Self1747     pub fn alpha_to_one_disabled(mut self) -> Self {
1748         self.multisample.alpha_to_one_enable = ash::vk::FALSE;
1749         self
1750     }
1751 
1752     /// Enables alpha-to-one. The alpha component of the first color output of the fragment shader
1753     /// will be replaced by the value `1.0`.
1754     ///
1755     /// Enabling alpha-to-one requires the `alpha_to_one` feature to be enabled on the device.
1756     ///
1757     /// Alpha-to-one is disabled by default.
1758     #[inline]
alpha_to_one_enabled(mut self) -> Self1759     pub fn alpha_to_one_enabled(mut self) -> Self {
1760         self.multisample.alpha_to_one_enable = ash::vk::TRUE;
1761         self
1762     }
1763 
1764     // TODO: rasterizationSamples and pSampleMask
1765 
1766     /// Sets the fragment shader to use.
1767     ///
1768     /// The fragment shader is run once for each pixel that is covered by each primitive.
1769     // TODO: correct specialization constants
1770     #[inline]
fragment_shader<'fs2, Fss2>( self, shader: GraphicsEntryPoint<'fs2>, specialization_constants: Fss2, ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2> where Fss2: SpecializationConstants,1771     pub fn fragment_shader<'fs2, Fss2>(
1772         self,
1773         shader: GraphicsEntryPoint<'fs2>,
1774         specialization_constants: Fss2,
1775     ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2>
1776     where
1777         Fss2: SpecializationConstants,
1778     {
1779         GraphicsPipelineBuilder {
1780             vertex_definition: self.vertex_definition,
1781             vertex_shader: self.vertex_shader,
1782             input_assembly: self.input_assembly,
1783             input_assembly_topology: self.input_assembly_topology,
1784             tessellation: self.tessellation,
1785             geometry_shader: self.geometry_shader,
1786             viewport: self.viewport,
1787             raster: self.raster,
1788             multisample: self.multisample,
1789             fragment_shader: Some((shader, specialization_constants)),
1790             depth_stencil: self.depth_stencil,
1791             blend: self.blend,
1792             subpass: self.subpass,
1793             cache: self.cache,
1794         }
1795     }
1796 
1797     /// Sets the depth/stencil configuration. This function may be removed in the future.
1798     #[inline]
depth_stencil(mut self, depth_stencil: DepthStencil) -> Self1799     pub fn depth_stencil(mut self, depth_stencil: DepthStencil) -> Self {
1800         self.depth_stencil = depth_stencil;
1801         self
1802     }
1803 
1804     /// Sets the depth/stencil tests as disabled.
1805     ///
1806     /// > **Note**: This is a shortcut for all the other `depth_*` and `depth_stencil_*` methods
1807     /// > of the builder.
1808     #[inline]
depth_stencil_disabled(mut self) -> Self1809     pub fn depth_stencil_disabled(mut self) -> Self {
1810         self.depth_stencil = DepthStencil::disabled();
1811         self
1812     }
1813 
1814     /// Sets the depth/stencil tests as a simple depth test and no stencil test.
1815     ///
1816     /// > **Note**: This is a shortcut for setting the depth test to `Less`, the depth write Into
1817     /// > ` true` and disable the stencil test.
1818     #[inline]
depth_stencil_simple_depth(mut self) -> Self1819     pub fn depth_stencil_simple_depth(mut self) -> Self {
1820         self.depth_stencil = DepthStencil::simple_depth_test();
1821         self
1822     }
1823 
1824     /// Sets whether the depth buffer will be written.
1825     #[inline]
depth_write(mut self, write: bool) -> Self1826     pub fn depth_write(mut self, write: bool) -> Self {
1827         self.depth_stencil.depth_write = write;
1828         self
1829     }
1830 
1831     // TODO: missing tons of depth-stencil stuff
1832 
1833     #[inline]
blend_collective(mut self, blend: AttachmentBlend) -> Self1834     pub fn blend_collective(mut self, blend: AttachmentBlend) -> Self {
1835         self.blend.attachments = AttachmentsBlend::Collective(blend);
1836         self
1837     }
1838 
1839     #[inline]
blend_individual<I>(mut self, blend: I) -> Self where I: IntoIterator<Item = AttachmentBlend>,1840     pub fn blend_individual<I>(mut self, blend: I) -> Self
1841     where
1842         I: IntoIterator<Item = AttachmentBlend>,
1843     {
1844         self.blend.attachments = AttachmentsBlend::Individual(blend.into_iter().collect());
1845         self
1846     }
1847 
1848     /// Each fragment shader output will have its value directly written to the framebuffer
1849     /// attachment. This is the default.
1850     #[inline]
blend_pass_through(self) -> Self1851     pub fn blend_pass_through(self) -> Self {
1852         self.blend_collective(AttachmentBlend::pass_through())
1853     }
1854 
1855     #[inline]
blend_alpha_blending(self) -> Self1856     pub fn blend_alpha_blending(self) -> Self {
1857         self.blend_collective(AttachmentBlend::alpha_blending())
1858     }
1859 
1860     #[inline]
blend_logic_op(mut self, logic_op: LogicOp) -> Self1861     pub fn blend_logic_op(mut self, logic_op: LogicOp) -> Self {
1862         self.blend.logic_op = Some(logic_op);
1863         self
1864     }
1865 
1866     /// Sets the logic operation as disabled. This is the default.
1867     #[inline]
blend_logic_op_disabled(mut self) -> Self1868     pub fn blend_logic_op_disabled(mut self) -> Self {
1869         self.blend.logic_op = None;
1870         self
1871     }
1872 
1873     /// Sets the blend constant. The default is `[0.0, 0.0, 0.0, 0.0]`.
1874     ///
1875     /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
1876     #[inline]
blend_constants(mut self, constants: [f32; 4]) -> Self1877     pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
1878         self.blend.blend_constants = Some(constants);
1879         self
1880     }
1881 
1882     /// Sets the blend constant value as dynamic. Its value will need to be set before drawing.
1883     ///
1884     /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
1885     #[inline]
blend_constants_dynamic(mut self) -> Self1886     pub fn blend_constants_dynamic(mut self) -> Self {
1887         self.blend.blend_constants = None;
1888         self
1889     }
1890 
1891     /// Sets the render pass subpass to use.
1892     #[inline]
render_pass(self, subpass: Subpass) -> Self1893     pub fn render_pass(self, subpass: Subpass) -> Self {
1894         GraphicsPipelineBuilder {
1895             vertex_definition: self.vertex_definition,
1896             vertex_shader: self.vertex_shader,
1897             input_assembly: self.input_assembly,
1898             input_assembly_topology: self.input_assembly_topology,
1899             tessellation: self.tessellation,
1900             geometry_shader: self.geometry_shader,
1901             viewport: self.viewport,
1902             raster: self.raster,
1903             multisample: self.multisample,
1904             fragment_shader: self.fragment_shader,
1905             depth_stencil: self.depth_stencil,
1906             blend: self.blend,
1907             subpass: Some(subpass),
1908             cache: self.cache,
1909         }
1910     }
1911 
1912     /// Enable caching of this pipeline via a PipelineCache object.
1913     ///
1914     /// If this pipeline already exists in the cache it will be used, if this is a new
1915     /// pipeline it will be inserted into the cache. The implementation handles the
1916     /// PipelineCache.
1917     #[inline]
build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self1918     pub fn build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self {
1919         self.cache = Some(pipeline_cache);
1920         self
1921     }
1922 }
1923 
1924 impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> Clone
1925     for GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
1926 where
1927     Vdef: Clone,
1928     Vss: Clone,
1929     Tcss: Clone,
1930     Tess: Clone,
1931     Gss: Clone,
1932     Fss: Clone,
1933 {
clone(&self) -> Self1934     fn clone(&self) -> Self {
1935         GraphicsPipelineBuilder {
1936             vertex_definition: self.vertex_definition.clone(),
1937             vertex_shader: self.vertex_shader.clone(),
1938             input_assembly: unsafe { ptr::read(&self.input_assembly) },
1939             input_assembly_topology: self.input_assembly_topology,
1940             tessellation: self.tessellation.clone(),
1941             geometry_shader: self.geometry_shader.clone(),
1942             viewport: self.viewport.clone(),
1943             raster: self.raster.clone(),
1944             multisample: self.multisample,
1945             fragment_shader: self.fragment_shader.clone(),
1946             depth_stencil: self.depth_stencil.clone(),
1947             blend: self.blend.clone(),
1948             subpass: self.subpass.clone(),
1949             cache: self.cache.clone(),
1950         }
1951     }
1952 }
1953