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