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