1 // Copyright (c) 2022 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 use super::CommandBufferBuilder; 11 use crate::{ 12 command_buffer::{ 13 allocator::CommandBufferAllocator, commands::dynamic_state::SetDynamicStateError, 14 }, 15 device::{DeviceOwned, QueueFlags}, 16 pipeline::{ 17 graphics::{ 18 color_blend::LogicOp, 19 depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps}, 20 input_assembly::PrimitiveTopology, 21 rasterization::{CullMode, DepthBias, FrontFace, LineStipple}, 22 viewport::{Scissor, Viewport}, 23 }, 24 DynamicState, 25 }, 26 RequiresOneOf, Version, VulkanObject, 27 }; 28 use smallvec::SmallVec; 29 use std::ops::RangeInclusive; 30 31 impl<L, A> CommandBufferBuilder<L, A> 32 where 33 A: CommandBufferAllocator, 34 { 35 // Helper function for dynamic state setting. 36 #[inline] validate_pipeline_fixed_state( &self, state: DynamicState, ) -> Result<(), SetDynamicStateError>37 fn validate_pipeline_fixed_state( 38 &self, 39 state: DynamicState, 40 ) -> Result<(), SetDynamicStateError> { 41 // VUID-vkCmdDispatch-None-02859 42 if self 43 .builder_state 44 .pipeline_graphics 45 .as_ref() 46 .map_or(false, |pipeline| { 47 matches!(pipeline.dynamic_state(state), Some(false)) 48 }) 49 { 50 return Err(SetDynamicStateError::PipelineHasFixedState); 51 } 52 53 Ok(()) 54 } 55 56 /// Sets the dynamic blend constants for future draw calls. 57 /// 58 /// # Panics 59 /// 60 /// - Panics if the queue family of the command buffer does not support graphics operations. 61 /// - Panics if the currently bound graphics pipeline already contains this state internally. 62 #[inline] set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self63 pub fn set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self { 64 self.validate_set_blend_constants(constants).unwrap(); 65 66 unsafe { self.set_blend_constants_unchecked(constants) } 67 } 68 validate_set_blend_constants( &self, _constants: [f32; 4], ) -> Result<(), SetDynamicStateError>69 fn validate_set_blend_constants( 70 &self, 71 _constants: [f32; 4], 72 ) -> Result<(), SetDynamicStateError> { 73 self.validate_pipeline_fixed_state(DynamicState::BlendConstants)?; 74 75 let queue_family_properties = self.queue_family_properties(); 76 77 // VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool 78 if !queue_family_properties 79 .queue_flags 80 .intersects(QueueFlags::GRAPHICS) 81 { 82 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 83 } 84 85 Ok(()) 86 } 87 88 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self89 pub unsafe fn set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self { 90 let fns = self.device().fns(); 91 (fns.v1_0.cmd_set_blend_constants)(self.handle(), &constants); 92 93 self.builder_state.blend_constants = Some(constants); 94 95 self.next_command_index += 1; 96 self 97 } 98 99 /// Sets whether dynamic color writes should be enabled for each attachment in the 100 /// framebuffer. 101 /// 102 /// # Panics 103 /// 104 /// - Panics if the queue family of the command buffer does not support graphics operations. 105 /// - Panics if the [`color_write_enable`] feature is not enabled on the device. 106 /// - Panics if the currently bound graphics pipeline already contains this state internally. 107 /// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal 108 /// [`attachments.len()`]. 109 /// 110 /// [`color_write_enable`]: crate::device::Features::color_write_enable 111 /// [`attachments.len()`]: crate::pipeline::graphics::color_blend::ColorBlendState::attachments 112 #[inline] set_color_write_enable<I>(&mut self, enables: I) -> &mut Self where I: IntoIterator<Item = bool>, I::IntoIter: ExactSizeIterator,113 pub fn set_color_write_enable<I>(&mut self, enables: I) -> &mut Self 114 where 115 I: IntoIterator<Item = bool>, 116 I::IntoIter: ExactSizeIterator, 117 { 118 let enables = enables.into_iter(); 119 self.validate_set_color_write_enable(&enables).unwrap(); 120 121 unsafe { self.set_color_write_enable_unchecked(enables) } 122 } 123 validate_set_color_write_enable( &self, enables: &impl ExactSizeIterator, ) -> Result<(), SetDynamicStateError>124 fn validate_set_color_write_enable( 125 &self, 126 enables: &impl ExactSizeIterator, 127 ) -> Result<(), SetDynamicStateError> { 128 self.validate_pipeline_fixed_state(DynamicState::ColorWriteEnable)?; 129 130 let queue_family_properties = self.queue_family_properties(); 131 132 // VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool 133 if !queue_family_properties 134 .queue_flags 135 .intersects(QueueFlags::GRAPHICS) 136 { 137 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 138 } 139 140 // VUID-vkCmdSetColorWriteEnableEXT-None-04803 141 if !self.device().enabled_features().color_write_enable { 142 return Err(SetDynamicStateError::RequirementNotMet { 143 required_for: "`CommandBufferBuilder::set_color_write_enable`", 144 requires_one_of: RequiresOneOf { 145 device_extensions: &["ext_color_write_enable"], 146 ..Default::default() 147 }, 148 }); 149 } 150 151 if let Some(color_blend_state) = self 152 .builder_state 153 .pipeline_graphics 154 .as_ref() 155 .and_then(|pipeline| pipeline.color_blend_state()) 156 { 157 // VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656 158 // Indirectly checked 159 if enables.len() != color_blend_state.attachments.len() { 160 return Err( 161 SetDynamicStateError::PipelineColorBlendAttachmentCountMismatch { 162 provided_count: enables.len() as u32, 163 required_count: color_blend_state.attachments.len() as u32, 164 }, 165 ); 166 } 167 } 168 169 Ok(()) 170 } 171 172 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_color_write_enable_unchecked( &mut self, enables: impl IntoIterator<Item = bool>, ) -> &mut Self173 pub unsafe fn set_color_write_enable_unchecked( 174 &mut self, 175 enables: impl IntoIterator<Item = bool>, 176 ) -> &mut Self { 177 let enables: SmallVec<[bool; 4]> = enables.into_iter().collect(); 178 179 if enables.is_empty() { 180 return self; 181 } 182 183 debug_assert!(self.device().enabled_extensions().ext_color_write_enable); 184 let enables_vk = enables 185 .iter() 186 .copied() 187 .map(ash::vk::Bool32::from) 188 .collect::<SmallVec<[_; 4]>>(); 189 190 let fns = self.device().fns(); 191 (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)( 192 self.handle(), 193 enables_vk.len() as u32, 194 enables_vk.as_ptr(), 195 ); 196 197 self.builder_state.color_write_enable = Some(enables); 198 199 self.next_command_index += 1; 200 self 201 } 202 203 /// Sets the dynamic cull mode for future draw calls. 204 /// 205 /// # Panics 206 /// 207 /// - Panics if the queue family of the command buffer does not support graphics operations. 208 /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`] 209 /// feature is not enabled on the device. 210 /// - Panics if the currently bound graphics pipeline already contains this state internally. 211 /// 212 /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state 213 #[inline] set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self214 pub fn set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self { 215 self.validate_set_cull_mode(cull_mode).unwrap(); 216 217 unsafe { self.set_cull_mode_unchecked(cull_mode) } 218 } 219 validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError>220 fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> { 221 self.validate_pipeline_fixed_state(DynamicState::CullMode)?; 222 223 // VUID-vkCmdSetCullMode-cullMode-parameter 224 cull_mode.validate_device(self.device())?; 225 226 let queue_family_properties = self.queue_family_properties(); 227 228 // VUID-vkCmdSetCullMode-commandBuffer-cmdpool 229 if !queue_family_properties 230 .queue_flags 231 .intersects(QueueFlags::GRAPHICS) 232 { 233 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 234 } 235 236 // VUID-vkCmdSetCullMode-None-03384 237 if !(self.device().api_version() >= Version::V1_3 238 || self.device().enabled_features().extended_dynamic_state) 239 { 240 return Err(SetDynamicStateError::RequirementNotMet { 241 required_for: "`CommandBufferBuilder::set_cull_mode`", 242 requires_one_of: RequiresOneOf { 243 api_version: Some(Version::V1_3), 244 features: &["extended_dynamic_state"], 245 ..Default::default() 246 }, 247 }); 248 } 249 250 Ok(()) 251 } 252 253 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self254 pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self { 255 let fns = self.device().fns(); 256 257 if self.device().api_version() >= Version::V1_3 { 258 (fns.v1_3.cmd_set_cull_mode)(self.handle(), cull_mode.into()); 259 } else { 260 debug_assert!( 261 self.device() 262 .enabled_extensions() 263 .ext_extended_dynamic_state 264 ); 265 (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle(), cull_mode.into()); 266 } 267 268 self.builder_state.cull_mode = Some(cull_mode); 269 270 self.next_command_index += 1; 271 self 272 } 273 274 /// Sets the dynamic depth bias values for future draw calls. 275 /// 276 /// # Panics 277 /// 278 /// - Panics if the queue family of the command buffer does not support graphics operations. 279 /// - Panics if the currently bound graphics pipeline already contains this state internally. 280 /// - If the [`depth_bias_clamp`] feature is not enabled on the device, panics if `clamp` is 281 /// not 0.0. 282 /// 283 /// [`depth_bias_clamp`]: crate::device::Features::depth_bias_clamp 284 #[inline] set_depth_bias( &mut self, constant_factor: f32, clamp: f32, slope_factor: f32, ) -> &mut Self285 pub fn set_depth_bias( 286 &mut self, 287 constant_factor: f32, 288 clamp: f32, 289 slope_factor: f32, 290 ) -> &mut Self { 291 self.validate_set_depth_bias(constant_factor, clamp, slope_factor) 292 .unwrap(); 293 294 unsafe { self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor) } 295 } 296 validate_set_depth_bias( &self, _constant_factor: f32, clamp: f32, _slope_factor: f32, ) -> Result<(), SetDynamicStateError>297 fn validate_set_depth_bias( 298 &self, 299 _constant_factor: f32, 300 clamp: f32, 301 _slope_factor: f32, 302 ) -> Result<(), SetDynamicStateError> { 303 self.validate_pipeline_fixed_state(DynamicState::DepthBias)?; 304 305 let queue_family_properties = self.queue_family_properties(); 306 307 // VUID-vkCmdSetDepthBias-commandBuffer-cmdpool 308 if !queue_family_properties 309 .queue_flags 310 .intersects(QueueFlags::GRAPHICS) 311 { 312 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 313 } 314 315 // VUID-vkCmdSetDepthBias-depthBiasClamp-00790 316 if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp { 317 return Err(SetDynamicStateError::RequirementNotMet { 318 required_for: "`clamp` is not `0.0`", 319 requires_one_of: RequiresOneOf { 320 features: &["depth_bias_clamp"], 321 ..Default::default() 322 }, 323 }); 324 } 325 326 Ok(()) 327 } 328 329 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_bias_unchecked( &mut self, constant_factor: f32, clamp: f32, slope_factor: f32, ) -> &mut Self330 pub unsafe fn set_depth_bias_unchecked( 331 &mut self, 332 constant_factor: f32, 333 clamp: f32, 334 slope_factor: f32, 335 ) -> &mut Self { 336 let fns = self.device().fns(); 337 (fns.v1_0.cmd_set_depth_bias)(self.handle(), constant_factor, clamp, slope_factor); 338 339 self.builder_state.depth_bias = Some(DepthBias { 340 constant_factor, 341 clamp, 342 slope_factor, 343 }); 344 345 self.next_command_index += 1; 346 self 347 } 348 349 /// Sets whether dynamic depth bias is enabled for future draw calls. 350 /// 351 /// # Panics 352 /// 353 /// - Panics if the queue family of the command buffer does not support graphics operations. 354 /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state2`] 355 /// feature is not enabled on the device. 356 /// - Panics if the currently bound graphics pipeline already contains this state internally. 357 /// 358 /// [`extended_dynamic_state2`]: crate::device::Features::extended_dynamic_state2 359 #[inline] set_depth_bias_enable(&mut self, enable: bool) -> &mut Self360 pub fn set_depth_bias_enable(&mut self, enable: bool) -> &mut Self { 361 self.validate_set_depth_bias_enable(enable).unwrap(); 362 363 unsafe { self.set_depth_bias_enable_unchecked(enable) } 364 } 365 validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>366 fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { 367 self.validate_pipeline_fixed_state(DynamicState::DepthBiasEnable)?; 368 369 let queue_family_properties = self.queue_family_properties(); 370 371 // VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool 372 if !queue_family_properties 373 .queue_flags 374 .intersects(QueueFlags::GRAPHICS) 375 { 376 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 377 } 378 379 // VUID-vkCmdSetDepthBiasEnable-None-04872 380 if !(self.device().api_version() >= Version::V1_3 381 || self.device().enabled_features().extended_dynamic_state2) 382 { 383 return Err(SetDynamicStateError::RequirementNotMet { 384 required_for: "`CommandBufferBuilder::set_depth_bias_enable`", 385 requires_one_of: RequiresOneOf { 386 api_version: Some(Version::V1_3), 387 features: &["extended_dynamic_state2"], 388 ..Default::default() 389 }, 390 }); 391 } 392 393 Ok(()) 394 } 395 396 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self397 pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self { 398 let fns = self.device().fns(); 399 400 if self.device().api_version() >= Version::V1_3 { 401 (fns.v1_3.cmd_set_depth_bias_enable)(self.handle(), enable.into()); 402 } else { 403 debug_assert!( 404 self.device() 405 .enabled_extensions() 406 .ext_extended_dynamic_state2 407 ); 408 (fns.ext_extended_dynamic_state2 409 .cmd_set_depth_bias_enable_ext)(self.handle(), enable.into()); 410 } 411 412 self.builder_state.depth_bias_enable = Some(enable); 413 414 self.next_command_index += 1; 415 self 416 } 417 418 /// Sets the dynamic depth bounds for future draw calls. 419 /// 420 /// # Panics 421 /// 422 /// - Panics if the queue family of the command buffer does not support graphics operations. 423 /// - Panics if the currently bound graphics pipeline already contains this state internally. 424 /// - If the [`ext_depth_range_unrestricted`] extension is not enabled on the device, panics if 425 /// the start and end of `bounds` are not between 0.0 and 1.0 inclusive. 426 /// 427 /// [`ext_depth_range_unrestricted`]: crate::device::DeviceExtensions::ext_depth_range_unrestricted set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self428 pub fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self { 429 self.validate_set_depth_bounds(bounds.clone()).unwrap(); 430 431 unsafe { self.set_depth_bounds_unchecked(bounds) } 432 } 433 validate_set_depth_bounds( &self, bounds: RangeInclusive<f32>, ) -> Result<(), SetDynamicStateError>434 fn validate_set_depth_bounds( 435 &self, 436 bounds: RangeInclusive<f32>, 437 ) -> Result<(), SetDynamicStateError> { 438 self.validate_pipeline_fixed_state(DynamicState::DepthBounds)?; 439 440 let queue_family_properties = self.queue_family_properties(); 441 442 // VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool 443 if !queue_family_properties 444 .queue_flags 445 .intersects(QueueFlags::GRAPHICS) 446 { 447 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 448 } 449 450 // VUID-vkCmdSetDepthBounds-minDepthBounds-00600 451 // VUID-vkCmdSetDepthBounds-maxDepthBounds-00601 452 if !self 453 .device() 454 .enabled_extensions() 455 .ext_depth_range_unrestricted 456 && !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end())) 457 { 458 return Err(SetDynamicStateError::RequirementNotMet { 459 required_for: "`bounds` is not between `0.0` and `1.0` inclusive", 460 requires_one_of: RequiresOneOf { 461 device_extensions: &["ext_depth_range_unrestricted"], 462 ..Default::default() 463 }, 464 }); 465 } 466 467 Ok(()) 468 } 469 470 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self471 pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self { 472 let fns = self.device().fns(); 473 (fns.v1_0.cmd_set_depth_bounds)(self.handle(), *bounds.start(), *bounds.end()); 474 475 self.builder_state.depth_bounds = Some(bounds); 476 477 self.next_command_index += 1; 478 self 479 } 480 481 /// Sets whether dynamic depth bounds testing is enabled for future draw calls. 482 /// 483 /// # Panics 484 /// 485 /// - Panics if the queue family of the command buffer does not support graphics operations. 486 /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`] 487 /// feature is not enabled on the device. 488 /// - Panics if the currently bound graphics pipeline already contains this state internally. 489 /// 490 /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state 491 #[inline] set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self492 pub fn set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self { 493 self.validate_set_depth_bounds_test_enable(enable).unwrap(); 494 495 unsafe { self.set_depth_bounds_test_enable_unchecked(enable) } 496 } 497 validate_set_depth_bounds_test_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>498 fn validate_set_depth_bounds_test_enable( 499 &self, 500 _enable: bool, 501 ) -> Result<(), SetDynamicStateError> { 502 self.validate_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?; 503 504 let queue_family_properties = self.queue_family_properties(); 505 506 // VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool 507 if !queue_family_properties 508 .queue_flags 509 .intersects(QueueFlags::GRAPHICS) 510 { 511 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 512 } 513 514 // VUID-vkCmdSetDepthBoundsTestEnable-None-03349 515 if !(self.device().api_version() >= Version::V1_3 516 || self.device().enabled_features().extended_dynamic_state) 517 { 518 return Err(SetDynamicStateError::RequirementNotMet { 519 required_for: "`CommandBufferBuilder::set_depth_bounds_test_enable`", 520 requires_one_of: RequiresOneOf { 521 api_version: Some(Version::V1_3), 522 features: &["extended_dynamic_state"], 523 ..Default::default() 524 }, 525 }); 526 } 527 528 Ok(()) 529 } 530 531 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self532 pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self { 533 let fns = self.device().fns(); 534 535 if self.device().api_version() >= Version::V1_3 { 536 (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle(), enable.into()); 537 } else { 538 debug_assert!( 539 self.device() 540 .enabled_extensions() 541 .ext_extended_dynamic_state 542 ); 543 (fns.ext_extended_dynamic_state 544 .cmd_set_depth_bounds_test_enable_ext)(self.handle(), enable.into()); 545 } 546 547 self.builder_state.depth_bounds_test_enable = Some(enable); 548 549 self.next_command_index += 1; 550 self 551 } 552 553 /// Sets the dynamic depth compare op for future draw calls. 554 /// 555 /// # Panics 556 /// 557 /// - Panics if the queue family of the command buffer does not support graphics operations. 558 /// - Panics if the device API version is less than 1.3 and the 559 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 560 /// not enabled on the device. 561 /// - Panics if the currently bound graphics pipeline already contains this state internally. 562 #[inline] set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self563 pub fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self { 564 self.validate_set_depth_compare_op(compare_op).unwrap(); 565 566 unsafe { self.set_depth_compare_op_unchecked(compare_op) } 567 } 568 validate_set_depth_compare_op( &self, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError>569 fn validate_set_depth_compare_op( 570 &self, 571 compare_op: CompareOp, 572 ) -> Result<(), SetDynamicStateError> { 573 self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?; 574 575 // VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter 576 compare_op.validate_device(self.device())?; 577 578 let queue_family_properties = self.queue_family_properties(); 579 580 // VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool 581 if !queue_family_properties 582 .queue_flags 583 .intersects(QueueFlags::GRAPHICS) 584 { 585 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 586 } 587 588 // VUID-vkCmdSetDepthCompareOp-None-03353 589 if !(self.device().api_version() >= Version::V1_3 590 || self.device().enabled_features().extended_dynamic_state) 591 { 592 return Err(SetDynamicStateError::RequirementNotMet { 593 required_for: "`CommandBufferBuilder::set_depth_compare_op`", 594 requires_one_of: RequiresOneOf { 595 api_version: Some(Version::V1_3), 596 features: &["extended_dynamic_state"], 597 ..Default::default() 598 }, 599 }); 600 } 601 602 Ok(()) 603 } 604 605 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self606 pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self { 607 let fns = self.device().fns(); 608 609 if self.device().api_version() >= Version::V1_3 { 610 (fns.v1_3.cmd_set_depth_compare_op)(self.handle(), compare_op.into()); 611 } else { 612 debug_assert!( 613 self.device() 614 .enabled_extensions() 615 .ext_extended_dynamic_state 616 ); 617 (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)( 618 self.handle(), 619 compare_op.into(), 620 ); 621 } 622 623 self.builder_state.depth_compare_op = Some(compare_op); 624 625 self.next_command_index += 1; 626 self 627 } 628 629 /// Sets whether dynamic depth testing is enabled for future draw calls. 630 /// 631 /// # Panics 632 /// 633 /// - Panics if the queue family of the command buffer does not support graphics operations. 634 /// - Panics if the device API version is less than 1.3 and the 635 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 636 /// not enabled on the device. 637 /// - Panics if the currently bound graphics pipeline already contains this state internally. 638 #[inline] set_depth_test_enable(&mut self, enable: bool) -> &mut Self639 pub fn set_depth_test_enable(&mut self, enable: bool) -> &mut Self { 640 self.validate_set_depth_test_enable(enable).unwrap(); 641 642 unsafe { self.set_depth_test_enable_unchecked(enable) } 643 } 644 validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>645 fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { 646 self.validate_pipeline_fixed_state(DynamicState::DepthTestEnable)?; 647 648 let queue_family_properties = self.queue_family_properties(); 649 650 // VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool 651 if !queue_family_properties 652 .queue_flags 653 .intersects(QueueFlags::GRAPHICS) 654 { 655 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 656 } 657 658 // VUID-vkCmdSetDepthTestEnable-None-03352 659 if !(self.device().api_version() >= Version::V1_3 660 || self.device().enabled_features().extended_dynamic_state) 661 { 662 return Err(SetDynamicStateError::RequirementNotMet { 663 required_for: "`CommandBufferBuilder::set_depth_test_enable`", 664 requires_one_of: RequiresOneOf { 665 api_version: Some(Version::V1_3), 666 features: &["extended_dynamic_state"], 667 ..Default::default() 668 }, 669 }); 670 } 671 672 Ok(()) 673 } 674 675 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self676 pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self { 677 let fns = self.device().fns(); 678 679 if self.device().api_version() >= Version::V1_3 { 680 (fns.v1_3.cmd_set_depth_test_enable)(self.handle(), enable.into()); 681 } else { 682 debug_assert!( 683 self.device() 684 .enabled_extensions() 685 .ext_extended_dynamic_state 686 ); 687 (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)( 688 self.handle(), 689 enable.into(), 690 ); 691 } 692 693 self.builder_state.depth_test_enable = Some(enable); 694 695 self.next_command_index += 1; 696 self 697 } 698 699 /// Sets whether dynamic depth write is enabled for future draw calls. 700 /// 701 /// # Panics 702 /// 703 /// - Panics if the queue family of the command buffer does not support graphics operations. 704 /// - Panics if the device API version is less than 1.3 and the 705 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 706 /// not enabled on the device. 707 /// - Panics if the currently bound graphics pipeline already contains this state internally. 708 #[inline] set_depth_write_enable(&mut self, enable: bool) -> &mut Self709 pub fn set_depth_write_enable(&mut self, enable: bool) -> &mut Self { 710 self.validate_set_depth_write_enable(enable).unwrap(); 711 712 unsafe { self.set_depth_write_enable_unchecked(enable) } 713 } 714 validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>715 fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { 716 self.validate_pipeline_fixed_state(DynamicState::DepthWriteEnable)?; 717 718 let queue_family_properties = self.queue_family_properties(); 719 720 // VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool 721 if !queue_family_properties 722 .queue_flags 723 .intersects(QueueFlags::GRAPHICS) 724 { 725 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 726 } 727 728 // VUID-vkCmdSetDepthWriteEnable-None-03354 729 if !(self.device().api_version() >= Version::V1_3 730 || self.device().enabled_features().extended_dynamic_state) 731 { 732 return Err(SetDynamicStateError::RequirementNotMet { 733 required_for: "`CommandBufferBuilder::set_depth_write_enable`", 734 requires_one_of: RequiresOneOf { 735 api_version: Some(Version::V1_3), 736 features: &["extended_dynamic_state"], 737 ..Default::default() 738 }, 739 }); 740 } 741 742 Ok(()) 743 } 744 745 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self746 pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self { 747 let fns = self.device().fns(); 748 749 if self.device().api_version() >= Version::V1_3 { 750 (fns.v1_3.cmd_set_depth_write_enable)(self.handle(), enable.into()); 751 } else { 752 debug_assert!( 753 self.device() 754 .enabled_extensions() 755 .ext_extended_dynamic_state 756 ); 757 (fns.ext_extended_dynamic_state 758 .cmd_set_depth_write_enable_ext)(self.handle(), enable.into()); 759 } 760 761 self.builder_state.depth_write_enable = Some(enable); 762 763 self.next_command_index += 1; 764 self 765 } 766 767 /// Sets the dynamic discard rectangles for future draw calls. 768 /// 769 /// # Panics 770 /// 771 /// - Panics if the queue family of the command buffer does not support graphics operations. 772 /// - Panics if the 773 /// [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles) 774 /// extension is not enabled on the device. 775 /// - Panics if the currently bound graphics pipeline already contains this state internally. 776 /// - Panics if the highest discard rectangle slot being set is greater than the 777 /// [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) device 778 /// property. set_discard_rectangle( &mut self, first_rectangle: u32, rectangles: impl IntoIterator<Item = Scissor>, ) -> &mut Self779 pub fn set_discard_rectangle( 780 &mut self, 781 first_rectangle: u32, 782 rectangles: impl IntoIterator<Item = Scissor>, 783 ) -> &mut Self { 784 let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect(); 785 self.validate_set_discard_rectangle(first_rectangle, &rectangles) 786 .unwrap(); 787 788 unsafe { self.set_discard_rectangle_unchecked(first_rectangle, rectangles) } 789 } 790 validate_set_discard_rectangle( &self, first_rectangle: u32, rectangles: &[Scissor], ) -> Result<(), SetDynamicStateError>791 fn validate_set_discard_rectangle( 792 &self, 793 first_rectangle: u32, 794 rectangles: &[Scissor], 795 ) -> Result<(), SetDynamicStateError> { 796 self.validate_pipeline_fixed_state(DynamicState::DiscardRectangle)?; 797 798 let queue_family_properties = self.queue_family_properties(); 799 800 // VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool 801 if !queue_family_properties 802 .queue_flags 803 .intersects(QueueFlags::GRAPHICS) 804 { 805 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 806 } 807 808 if self.device().enabled_extensions().ext_discard_rectangles { 809 return Err(SetDynamicStateError::RequirementNotMet { 810 required_for: "`CommandBufferBuilder::set_discard_rectangle`", 811 requires_one_of: RequiresOneOf { 812 device_extensions: &["ext_discard_rectangles"], 813 ..Default::default() 814 }, 815 }); 816 } 817 818 // VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585 819 if first_rectangle + rectangles.len() as u32 820 > self 821 .device() 822 .physical_device() 823 .properties() 824 .max_discard_rectangles 825 .unwrap() 826 { 827 return Err(SetDynamicStateError::MaxDiscardRectanglesExceeded { 828 provided: first_rectangle + rectangles.len() as u32, 829 max: self 830 .device() 831 .physical_device() 832 .properties() 833 .max_discard_rectangles 834 .unwrap(), 835 }); 836 } 837 838 Ok(()) 839 } 840 841 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_discard_rectangle_unchecked( &mut self, first_rectangle: u32, rectangles: impl IntoIterator<Item = Scissor>, ) -> &mut Self842 pub unsafe fn set_discard_rectangle_unchecked( 843 &mut self, 844 first_rectangle: u32, 845 rectangles: impl IntoIterator<Item = Scissor>, 846 ) -> &mut Self { 847 let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect(); 848 849 if rectangles.is_empty() { 850 return self; 851 } 852 853 debug_assert!(self.device().enabled_extensions().ext_discard_rectangles); 854 855 let rectangles_vk = rectangles 856 .iter() 857 .copied() 858 .map(ash::vk::Rect2D::from) 859 .collect::<SmallVec<[_; 2]>>(); 860 861 debug_assert!( 862 first_rectangle + rectangles.len() as u32 863 <= self 864 .device() 865 .physical_device() 866 .properties() 867 .max_discard_rectangles 868 .unwrap() 869 ); 870 871 let fns = self.device().fns(); 872 (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)( 873 self.handle(), 874 first_rectangle, 875 rectangles_vk.len() as u32, 876 rectangles_vk.as_ptr(), 877 ); 878 879 for (num, rectangle) in rectangles.iter().enumerate() { 880 let num = num as u32 + first_rectangle; 881 self.builder_state.discard_rectangle.insert(num, *rectangle); 882 } 883 884 self.next_command_index += 1; 885 self 886 } 887 888 /// Sets the dynamic front face for future draw calls. 889 /// 890 /// # Panics 891 /// 892 /// - Panics if the queue family of the command buffer does not support graphics operations. 893 /// - Panics if the device API version is less than 1.3 and the 894 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 895 /// not enabled on the device. 896 /// - Panics if the currently bound graphics pipeline already contains this state internally. 897 #[inline] set_front_face(&mut self, face: FrontFace) -> &mut Self898 pub fn set_front_face(&mut self, face: FrontFace) -> &mut Self { 899 self.validate_set_front_face(face).unwrap(); 900 901 unsafe { self.set_front_face_unchecked(face) } 902 } 903 validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError>904 fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> { 905 self.validate_pipeline_fixed_state(DynamicState::FrontFace)?; 906 907 // VUID-vkCmdSetFrontFace-frontFace-parameter 908 face.validate_device(self.device())?; 909 910 let queue_family_properties = self.queue_family_properties(); 911 912 // VUID-vkCmdSetFrontFace-commandBuffer-cmdpool 913 if !queue_family_properties 914 .queue_flags 915 .intersects(QueueFlags::GRAPHICS) 916 { 917 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 918 } 919 920 // VUID-vkCmdSetFrontFace-None-03383 921 if !(self.device().api_version() >= Version::V1_3 922 || self.device().enabled_features().extended_dynamic_state) 923 { 924 return Err(SetDynamicStateError::RequirementNotMet { 925 required_for: "`CommandBufferBuilder::set_front_face`", 926 requires_one_of: RequiresOneOf { 927 api_version: Some(Version::V1_3), 928 features: &["extended_dynamic_state"], 929 ..Default::default() 930 }, 931 }); 932 } 933 934 Ok(()) 935 } 936 937 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self938 pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self { 939 let fns = self.device().fns(); 940 941 if self.device().api_version() >= Version::V1_3 { 942 (fns.v1_3.cmd_set_front_face)(self.handle(), face.into()); 943 } else { 944 debug_assert!( 945 self.device() 946 .enabled_extensions() 947 .ext_extended_dynamic_state 948 ); 949 (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle(), face.into()); 950 } 951 952 self.builder_state.front_face = Some(face); 953 954 self.next_command_index += 1; 955 self 956 } 957 958 /// Sets the dynamic line stipple values for future draw calls. 959 /// 960 /// # Panics 961 /// 962 /// - Panics if the queue family of the command buffer does not support graphics operations. 963 /// - Panics if the [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization) 964 /// extension is not enabled on the device. 965 /// - Panics if the currently bound graphics pipeline already contains this state internally. 966 /// - Panics if `factor` is not between 1 and 256 inclusive. 967 #[inline] set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self968 pub fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self { 969 self.validate_set_line_stipple(factor, pattern).unwrap(); 970 971 unsafe { self.set_line_stipple_unchecked(factor, pattern) } 972 } 973 validate_set_line_stipple( &self, factor: u32, _pattern: u16, ) -> Result<(), SetDynamicStateError>974 fn validate_set_line_stipple( 975 &self, 976 factor: u32, 977 _pattern: u16, 978 ) -> Result<(), SetDynamicStateError> { 979 self.validate_pipeline_fixed_state(DynamicState::LineStipple)?; 980 981 let queue_family_properties = self.queue_family_properties(); 982 983 // VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool 984 if !queue_family_properties 985 .queue_flags 986 .intersects(QueueFlags::GRAPHICS) 987 { 988 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 989 } 990 991 if !self.device().enabled_extensions().ext_line_rasterization { 992 return Err(SetDynamicStateError::RequirementNotMet { 993 required_for: "`CommandBufferBuilder::set_line_stipple`", 994 requires_one_of: RequiresOneOf { 995 device_extensions: &["ext_line_rasterization"], 996 ..Default::default() 997 }, 998 }); 999 } 1000 1001 // VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776 1002 if !(1..=256).contains(&factor) { 1003 return Err(SetDynamicStateError::FactorOutOfRange); 1004 } 1005 1006 Ok(()) 1007 } 1008 1009 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self1010 pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self { 1011 debug_assert!(self.device().enabled_extensions().ext_line_rasterization); 1012 let fns = self.device().fns(); 1013 (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle(), factor, pattern); 1014 1015 self.builder_state.line_stipple = Some(LineStipple { factor, pattern }); 1016 1017 self.next_command_index += 1; 1018 self 1019 } 1020 1021 /// Sets the dynamic line width for future draw calls. 1022 /// 1023 /// # Panics 1024 /// 1025 /// - Panics if the queue family of the command buffer does not support graphics operations. 1026 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1027 /// - If the [`wide_lines`](crate::device::Features::wide_lines) feature is not enabled, panics 1028 /// if `line_width` is not 1.0. set_line_width(&mut self, line_width: f32) -> &mut Self1029 pub fn set_line_width(&mut self, line_width: f32) -> &mut Self { 1030 self.validate_set_line_width(line_width).unwrap(); 1031 1032 unsafe { self.set_line_width_unchecked(line_width) } 1033 } 1034 validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError>1035 fn validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError> { 1036 self.validate_pipeline_fixed_state(DynamicState::LineWidth)?; 1037 1038 let queue_family_properties = self.queue_family_properties(); 1039 1040 // VUID-vkCmdSetLineWidth-commandBuffer-cmdpool 1041 if !queue_family_properties 1042 .queue_flags 1043 .intersects(QueueFlags::GRAPHICS) 1044 { 1045 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1046 } 1047 1048 // VUID-vkCmdSetLineWidth-lineWidth-00788 1049 if !self.device().enabled_features().wide_lines && line_width != 1.0 { 1050 return Err(SetDynamicStateError::RequirementNotMet { 1051 required_for: "`line_width` is not `1.0`", 1052 requires_one_of: RequiresOneOf { 1053 features: &["wide_lines"], 1054 ..Default::default() 1055 }, 1056 }); 1057 } 1058 1059 Ok(()) 1060 } 1061 1062 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self1063 pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self { 1064 let fns = self.device().fns(); 1065 (fns.v1_0.cmd_set_line_width)(self.handle(), line_width); 1066 1067 self.builder_state.line_width = Some(line_width); 1068 1069 self.next_command_index += 1; 1070 self 1071 } 1072 1073 /// Sets the dynamic logic op for future draw calls. 1074 /// 1075 /// # Panics 1076 /// 1077 /// - Panics if the queue family of the command buffer does not support graphics operations. 1078 /// - Panics if the 1079 /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op) 1080 /// feature is not enabled on the device. 1081 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1082 #[inline] set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self1083 pub fn set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self { 1084 self.validate_set_logic_op(logic_op).unwrap(); 1085 1086 unsafe { self.set_logic_op_unchecked(logic_op) } 1087 } 1088 validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError>1089 fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> { 1090 self.validate_pipeline_fixed_state(DynamicState::LogicOp)?; 1091 1092 // VUID-vkCmdSetLogicOpEXT-logicOp-parameter 1093 logic_op.validate_device(self.device())?; 1094 1095 let queue_family_properties = self.queue_family_properties(); 1096 1097 // VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool 1098 if !queue_family_properties 1099 .queue_flags 1100 .intersects(QueueFlags::GRAPHICS) 1101 { 1102 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1103 } 1104 1105 // VUID-vkCmdSetLogicOpEXT-None-04867 1106 if !self 1107 .device() 1108 .enabled_features() 1109 .extended_dynamic_state2_logic_op 1110 { 1111 return Err(SetDynamicStateError::RequirementNotMet { 1112 required_for: "`CommandBufferBuilder::set_logic_op`", 1113 requires_one_of: RequiresOneOf { 1114 features: &["extended_dynamic_state2_logic_op"], 1115 ..Default::default() 1116 }, 1117 }); 1118 } 1119 1120 Ok(()) 1121 } 1122 1123 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self1124 pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self { 1125 debug_assert!( 1126 self.device() 1127 .enabled_extensions() 1128 .ext_extended_dynamic_state2 1129 ); 1130 debug_assert!( 1131 self.device() 1132 .enabled_features() 1133 .extended_dynamic_state2_logic_op 1134 ); 1135 let fns = self.device().fns(); 1136 (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle(), logic_op.into()); 1137 1138 self.builder_state.logic_op = Some(logic_op); 1139 1140 self.next_command_index += 1; 1141 self 1142 } 1143 1144 /// Sets the dynamic number of patch control points for future draw calls. 1145 /// 1146 /// # Panics 1147 /// 1148 /// - Panics if the queue family of the command buffer does not support graphics operations. 1149 /// - Panics if the 1150 /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points) 1151 /// feature is not enabled on the device. 1152 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1153 /// - Panics if `num` is 0. 1154 /// - Panics if `num` is greater than the 1155 /// [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size) 1156 /// property of the device. 1157 #[inline] set_patch_control_points(&mut self, num: u32) -> &mut Self1158 pub fn set_patch_control_points(&mut self, num: u32) -> &mut Self { 1159 self.validate_set_patch_control_points(num).unwrap(); 1160 1161 unsafe { self.set_patch_control_points_unchecked(num) } 1162 } 1163 validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError>1164 fn validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError> { 1165 self.validate_pipeline_fixed_state(DynamicState::PatchControlPoints)?; 1166 1167 let queue_family_properties = self.queue_family_properties(); 1168 1169 // VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool 1170 if !queue_family_properties 1171 .queue_flags 1172 .intersects(QueueFlags::GRAPHICS) 1173 { 1174 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1175 } 1176 1177 // VUID-vkCmdSetPatchControlPointsEXT-None-04873 1178 if !self 1179 .device() 1180 .enabled_features() 1181 .extended_dynamic_state2_patch_control_points 1182 { 1183 return Err(SetDynamicStateError::RequirementNotMet { 1184 required_for: "`CommandBufferBuilder::set_patch_control_points`", 1185 requires_one_of: RequiresOneOf { 1186 features: &["extended_dynamic_state2_patch_control_points"], 1187 ..Default::default() 1188 }, 1189 }); 1190 } 1191 1192 // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874 1193 assert!(num > 0, "num must be greater than 0"); 1194 1195 // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874 1196 if num 1197 > self 1198 .device() 1199 .physical_device() 1200 .properties() 1201 .max_tessellation_patch_size 1202 { 1203 return Err(SetDynamicStateError::MaxTessellationPatchSizeExceeded { 1204 provided: num, 1205 max: self 1206 .device() 1207 .physical_device() 1208 .properties() 1209 .max_tessellation_patch_size, 1210 }); 1211 } 1212 1213 Ok(()) 1214 } 1215 1216 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self1217 pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self { 1218 debug_assert!( 1219 self.device() 1220 .enabled_extensions() 1221 .ext_extended_dynamic_state2 1222 ); 1223 let fns = self.device().fns(); 1224 (fns.ext_extended_dynamic_state2 1225 .cmd_set_patch_control_points_ext)(self.handle(), num); 1226 1227 self.builder_state.patch_control_points = Some(num); 1228 1229 self.next_command_index += 1; 1230 self 1231 } 1232 1233 /// Sets whether dynamic primitive restart is enabled for future draw calls. 1234 /// 1235 /// # Panics 1236 /// 1237 /// - Panics if the queue family of the command buffer does not support graphics operations. 1238 /// - Panics if the device API version is less than 1.3 and the 1239 /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is 1240 /// not enabled on the device. 1241 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1242 #[inline] set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self1243 pub fn set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self { 1244 self.validate_set_primitive_restart_enable(enable).unwrap(); 1245 1246 unsafe { self.set_primitive_restart_enable_unchecked(enable) } 1247 } 1248 validate_set_primitive_restart_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>1249 fn validate_set_primitive_restart_enable( 1250 &self, 1251 _enable: bool, 1252 ) -> Result<(), SetDynamicStateError> { 1253 self.validate_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?; 1254 1255 let queue_family_properties = self.queue_family_properties(); 1256 1257 // VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool 1258 if !queue_family_properties 1259 .queue_flags 1260 .intersects(QueueFlags::GRAPHICS) 1261 { 1262 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1263 } 1264 1265 // VUID-vkCmdSetPrimitiveRestartEnable-None-04866 1266 if !(self.device().api_version() >= Version::V1_3 1267 || self.device().enabled_features().extended_dynamic_state2) 1268 { 1269 return Err(SetDynamicStateError::RequirementNotMet { 1270 required_for: "`CommandBufferBuilder::set_primitive_restart_enable`", 1271 requires_one_of: RequiresOneOf { 1272 api_version: Some(Version::V1_3), 1273 features: &["extended_dynamic_state2"], 1274 ..Default::default() 1275 }, 1276 }); 1277 } 1278 1279 Ok(()) 1280 } 1281 1282 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self1283 pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self { 1284 let fns = self.device().fns(); 1285 1286 if self.device().api_version() >= Version::V1_3 { 1287 (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle(), enable.into()); 1288 } else { 1289 debug_assert!( 1290 self.device() 1291 .enabled_extensions() 1292 .ext_extended_dynamic_state2 1293 ); 1294 (fns.ext_extended_dynamic_state2 1295 .cmd_set_primitive_restart_enable_ext)(self.handle(), enable.into()); 1296 } 1297 1298 self.builder_state.primitive_restart_enable = Some(enable); 1299 1300 self.next_command_index += 1; 1301 self 1302 } 1303 1304 /// Sets the dynamic primitive topology for future draw calls. 1305 /// 1306 /// # Panics 1307 /// 1308 /// - Panics if the queue family of the command buffer does not support graphics operations. 1309 /// - Panics if the device API version is less than 1.3 and the 1310 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 1311 /// not enabled on the device. 1312 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1313 /// - If the [`geometry_shader`](crate::device::Features::geometry_shader) feature is not 1314 /// enabled, panics if `topology` is a `WithAdjacency` topology. 1315 /// - If the [`tessellation_shader`](crate::device::Features::tessellation_shader) feature is 1316 /// not enabled, panics if `topology` is `PatchList`. 1317 #[inline] set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self1318 pub fn set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self { 1319 self.validate_set_primitive_topology(topology).unwrap(); 1320 1321 unsafe { self.set_primitive_topology_unchecked(topology) } 1322 } 1323 validate_set_primitive_topology( &self, topology: PrimitiveTopology, ) -> Result<(), SetDynamicStateError>1324 fn validate_set_primitive_topology( 1325 &self, 1326 topology: PrimitiveTopology, 1327 ) -> Result<(), SetDynamicStateError> { 1328 self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?; 1329 1330 // VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter 1331 topology.validate_device(self.device())?; 1332 1333 let queue_family_properties = self.queue_family_properties(); 1334 1335 // VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool 1336 if !queue_family_properties 1337 .queue_flags 1338 .intersects(QueueFlags::GRAPHICS) 1339 { 1340 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1341 } 1342 1343 // VUID-vkCmdSetPrimitiveTopology-None-03347 1344 if !(self.device().api_version() >= Version::V1_3 1345 || self.device().enabled_features().extended_dynamic_state) 1346 { 1347 return Err(SetDynamicStateError::RequirementNotMet { 1348 required_for: "`CommandBufferBuilder::set_primitive_topology`", 1349 requires_one_of: RequiresOneOf { 1350 api_version: Some(Version::V1_3), 1351 features: &["extended_dynamic_state"], 1352 ..Default::default() 1353 }, 1354 }); 1355 } 1356 1357 // VUID? 1358 // Since these requirements exist for fixed state when creating the pipeline, 1359 // I assume they exist for dynamic state as well. 1360 match topology { 1361 PrimitiveTopology::TriangleFan => { 1362 if self.device().enabled_extensions().khr_portability_subset 1363 && !self.device().enabled_features().triangle_fans 1364 { 1365 return Err(SetDynamicStateError::RequirementNotMet { 1366 required_for: "this device is a portability subset device, and `topology` \ 1367 is `PrimitiveTopology::TriangleFan`", 1368 requires_one_of: RequiresOneOf { 1369 features: &["triangle_fans"], 1370 ..Default::default() 1371 }, 1372 }); 1373 } 1374 } 1375 PrimitiveTopology::LineListWithAdjacency 1376 | PrimitiveTopology::LineStripWithAdjacency 1377 | PrimitiveTopology::TriangleListWithAdjacency 1378 | PrimitiveTopology::TriangleStripWithAdjacency => { 1379 if !self.device().enabled_features().geometry_shader { 1380 return Err(SetDynamicStateError::RequirementNotMet { 1381 required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`", 1382 requires_one_of: RequiresOneOf { 1383 features: &["geometry_shader"], 1384 ..Default::default() 1385 }, 1386 }); 1387 } 1388 } 1389 PrimitiveTopology::PatchList => { 1390 if !self.device().enabled_features().tessellation_shader { 1391 return Err(SetDynamicStateError::RequirementNotMet { 1392 required_for: "`topology` is `PrimitiveTopology::PatchList`", 1393 requires_one_of: RequiresOneOf { 1394 features: &["tessellation_shader"], 1395 ..Default::default() 1396 }, 1397 }); 1398 } 1399 } 1400 _ => (), 1401 } 1402 1403 Ok(()) 1404 } 1405 1406 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_primitive_topology_unchecked( &mut self, topology: PrimitiveTopology, ) -> &mut Self1407 pub unsafe fn set_primitive_topology_unchecked( 1408 &mut self, 1409 topology: PrimitiveTopology, 1410 ) -> &mut Self { 1411 let fns = self.device().fns(); 1412 1413 if self.device().api_version() >= Version::V1_3 { 1414 (fns.v1_3.cmd_set_primitive_topology)(self.handle(), topology.into()); 1415 } else { 1416 debug_assert!( 1417 self.device() 1418 .enabled_extensions() 1419 .ext_extended_dynamic_state 1420 ); 1421 (fns.ext_extended_dynamic_state 1422 .cmd_set_primitive_topology_ext)(self.handle(), topology.into()); 1423 } 1424 1425 self.builder_state.primitive_topology = Some(topology); 1426 1427 self.next_command_index += 1; 1428 self 1429 } 1430 1431 /// Sets whether dynamic rasterizer discard is enabled for future draw calls. 1432 /// 1433 /// # Panics 1434 /// 1435 /// - Panics if the queue family of the command buffer does not support graphics operations. 1436 /// - Panics if the device API version is less than 1.3 and the 1437 /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is 1438 /// not enabled on the device. 1439 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1440 #[inline] set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self1441 pub fn set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self { 1442 self.validate_set_rasterizer_discard_enable(enable).unwrap(); 1443 1444 unsafe { self.set_rasterizer_discard_enable_unchecked(enable) } 1445 } 1446 validate_set_rasterizer_discard_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>1447 fn validate_set_rasterizer_discard_enable( 1448 &self, 1449 _enable: bool, 1450 ) -> Result<(), SetDynamicStateError> { 1451 self.validate_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?; 1452 1453 let queue_family_properties = self.queue_family_properties(); 1454 1455 // VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool 1456 if !queue_family_properties 1457 .queue_flags 1458 .intersects(QueueFlags::GRAPHICS) 1459 { 1460 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1461 } 1462 1463 // VUID-vkCmdSetRasterizerDiscardEnable-None-04871 1464 if !(self.device().api_version() >= Version::V1_3 1465 || self.device().enabled_features().extended_dynamic_state2) 1466 { 1467 return Err(SetDynamicStateError::RequirementNotMet { 1468 required_for: "`CommandBufferBuilder::set_rasterizer_discard_enable`", 1469 requires_one_of: RequiresOneOf { 1470 api_version: Some(Version::V1_3), 1471 features: &["extended_dynamic_state2"], 1472 ..Default::default() 1473 }, 1474 }); 1475 } 1476 1477 Ok(()) 1478 } 1479 1480 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self1481 pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self { 1482 let fns = self.device().fns(); 1483 1484 if self.device().api_version() >= Version::V1_3 { 1485 (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle(), enable.into()); 1486 } else { 1487 debug_assert!( 1488 self.device() 1489 .enabled_extensions() 1490 .ext_extended_dynamic_state2 1491 ); 1492 (fns.ext_extended_dynamic_state2 1493 .cmd_set_rasterizer_discard_enable_ext)(self.handle(), enable.into()); 1494 } 1495 1496 self.builder_state.rasterizer_discard_enable = Some(enable); 1497 1498 self.next_command_index += 1; 1499 self 1500 } 1501 1502 /// Sets the dynamic scissors for future draw calls. 1503 /// 1504 /// # Panics 1505 /// 1506 /// - Panics if the queue family of the command buffer does not support graphics operations. 1507 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1508 /// - Panics if the highest scissor slot being set is greater than the 1509 /// [`max_viewports`](crate::device::Properties::max_viewports) device property. 1510 /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, 1511 /// panics if `first_scissor` is not 0, or if more than 1 scissor is provided. 1512 #[inline] set_scissor( &mut self, first_scissor: u32, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1513 pub fn set_scissor( 1514 &mut self, 1515 first_scissor: u32, 1516 scissors: impl IntoIterator<Item = Scissor>, 1517 ) -> &mut Self { 1518 let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); 1519 self.validate_set_scissor(first_scissor, &scissors).unwrap(); 1520 1521 unsafe { self.set_scissor_unchecked(first_scissor, scissors) } 1522 } 1523 validate_set_scissor( &self, first_scissor: u32, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError>1524 fn validate_set_scissor( 1525 &self, 1526 first_scissor: u32, 1527 scissors: &[Scissor], 1528 ) -> Result<(), SetDynamicStateError> { 1529 self.validate_pipeline_fixed_state(DynamicState::Scissor)?; 1530 1531 let queue_family_properties = self.queue_family_properties(); 1532 1533 // VUID-vkCmdSetScissor-commandBuffer-cmdpool 1534 if !queue_family_properties 1535 .queue_flags 1536 .intersects(QueueFlags::GRAPHICS) 1537 { 1538 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1539 } 1540 1541 // VUID-vkCmdSetScissor-firstScissor-00592 1542 if first_scissor + scissors.len() as u32 1543 > self.device().physical_device().properties().max_viewports 1544 { 1545 return Err(SetDynamicStateError::MaxViewportsExceeded { 1546 provided: first_scissor + scissors.len() as u32, 1547 max: self.device().physical_device().properties().max_viewports, 1548 }); 1549 } 1550 1551 if !self.device().enabled_features().multi_viewport { 1552 // VUID-vkCmdSetScissor-firstScissor-00593 1553 if first_scissor != 0 { 1554 return Err(SetDynamicStateError::RequirementNotMet { 1555 required_for: "`first_scissor` is not `0`", 1556 requires_one_of: RequiresOneOf { 1557 features: &["multi_viewport"], 1558 ..Default::default() 1559 }, 1560 }); 1561 } 1562 1563 // VUID-vkCmdSetScissor-scissorCount-00594 1564 if scissors.len() > 1 { 1565 return Err(SetDynamicStateError::RequirementNotMet { 1566 required_for: "`scissors.len()` is greater than `1`", 1567 requires_one_of: RequiresOneOf { 1568 features: &["multi_viewport"], 1569 ..Default::default() 1570 }, 1571 }); 1572 } 1573 } 1574 1575 Ok(()) 1576 } 1577 1578 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_scissor_unchecked( &mut self, first_scissor: u32, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1579 pub unsafe fn set_scissor_unchecked( 1580 &mut self, 1581 first_scissor: u32, 1582 scissors: impl IntoIterator<Item = Scissor>, 1583 ) -> &mut Self { 1584 let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); 1585 1586 if scissors.is_empty() { 1587 return self; 1588 } 1589 1590 let scissors_vk = scissors 1591 .iter() 1592 .copied() 1593 .map(ash::vk::Rect2D::from) 1594 .collect::<SmallVec<[_; 2]>>(); 1595 1596 let fns = self.device().fns(); 1597 (fns.v1_0.cmd_set_scissor)( 1598 self.handle(), 1599 first_scissor, 1600 scissors_vk.len() as u32, 1601 scissors_vk.as_ptr(), 1602 ); 1603 1604 for (num, scissor) in scissors.iter().enumerate() { 1605 let num = num as u32 + first_scissor; 1606 self.builder_state.scissor.insert(num, *scissor); 1607 } 1608 1609 self.next_command_index += 1; 1610 self 1611 } 1612 1613 /// Sets the dynamic scissors with count for future draw calls. 1614 /// 1615 /// # Panics 1616 /// 1617 /// - Panics if the queue family of the command buffer does not support graphics operations. 1618 /// - Panics if the device API version is less than 1.3 and the 1619 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 1620 /// not enabled on the device. 1621 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1622 /// - Panics if the highest scissor slot being set is greater than the 1623 /// [`max_viewports`](crate::device::Properties::max_viewports) device property. 1624 /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, 1625 /// panics if more than 1 scissor is provided. 1626 #[inline] set_scissor_with_count( &mut self, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1627 pub fn set_scissor_with_count( 1628 &mut self, 1629 scissors: impl IntoIterator<Item = Scissor>, 1630 ) -> &mut Self { 1631 let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); 1632 self.validate_set_scissor_with_count(&scissors).unwrap(); 1633 1634 unsafe { self.set_scissor_with_count_unchecked(scissors) } 1635 } 1636 validate_set_scissor_with_count( &self, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError>1637 fn validate_set_scissor_with_count( 1638 &self, 1639 scissors: &[Scissor], 1640 ) -> Result<(), SetDynamicStateError> { 1641 self.validate_pipeline_fixed_state(DynamicState::ScissorWithCount)?; 1642 1643 let queue_family_properties = self.queue_family_properties(); 1644 1645 // VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool 1646 if !queue_family_properties 1647 .queue_flags 1648 .intersects(QueueFlags::GRAPHICS) 1649 { 1650 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1651 } 1652 1653 // VUID-vkCmdSetScissorWithCount-None-03396 1654 if !(self.device().api_version() >= Version::V1_3 1655 || self.device().enabled_features().extended_dynamic_state) 1656 { 1657 return Err(SetDynamicStateError::RequirementNotMet { 1658 required_for: "`CommandBufferBuilder::set_scissor_with_count`", 1659 requires_one_of: RequiresOneOf { 1660 api_version: Some(Version::V1_3), 1661 features: &["extended_dynamic_state"], 1662 ..Default::default() 1663 }, 1664 }); 1665 } 1666 1667 // VUID-vkCmdSetScissorWithCount-scissorCount-03397 1668 if scissors.len() as u32 > self.device().physical_device().properties().max_viewports { 1669 return Err(SetDynamicStateError::MaxViewportsExceeded { 1670 provided: scissors.len() as u32, 1671 max: self.device().physical_device().properties().max_viewports, 1672 }); 1673 } 1674 1675 // VUID-vkCmdSetScissorWithCount-scissorCount-03398 1676 if !self.device().enabled_features().multi_viewport && scissors.len() > 1 { 1677 return Err(SetDynamicStateError::RequirementNotMet { 1678 required_for: "`scissors.len()` is greater than `1`", 1679 requires_one_of: RequiresOneOf { 1680 features: &["multi_viewport"], 1681 ..Default::default() 1682 }, 1683 }); 1684 } 1685 1686 Ok(()) 1687 } 1688 1689 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_scissor_with_count_unchecked( &mut self, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1690 pub unsafe fn set_scissor_with_count_unchecked( 1691 &mut self, 1692 scissors: impl IntoIterator<Item = Scissor>, 1693 ) -> &mut Self { 1694 let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); 1695 1696 if scissors.is_empty() { 1697 return self; 1698 } 1699 1700 let scissors_vk = scissors 1701 .iter() 1702 .copied() 1703 .map(ash::vk::Rect2D::from) 1704 .collect::<SmallVec<[_; 2]>>(); 1705 1706 let fns = self.device().fns(); 1707 1708 if self.device().api_version() >= Version::V1_3 { 1709 (fns.v1_3.cmd_set_scissor_with_count)( 1710 self.handle(), 1711 scissors_vk.len() as u32, 1712 scissors_vk.as_ptr(), 1713 ); 1714 } else { 1715 debug_assert!( 1716 self.device() 1717 .enabled_extensions() 1718 .ext_extended_dynamic_state 1719 ); 1720 (fns.ext_extended_dynamic_state 1721 .cmd_set_scissor_with_count_ext)( 1722 self.handle(), 1723 scissors_vk.len() as u32, 1724 scissors_vk.as_ptr(), 1725 ); 1726 } 1727 1728 self.builder_state.scissor_with_count = Some(scissors); 1729 1730 self.next_command_index += 1; 1731 self 1732 } 1733 1734 /// Sets the dynamic stencil compare mask on one or both faces for future draw calls. 1735 /// 1736 /// # Panics 1737 /// 1738 /// - Panics if the queue family of the command buffer does not support graphics operations. 1739 /// - Panics if the currently bound graphics pipeline already contains this state internally. set_stencil_compare_mask( &mut self, faces: StencilFaces, compare_mask: u32, ) -> &mut Self1740 pub fn set_stencil_compare_mask( 1741 &mut self, 1742 faces: StencilFaces, 1743 compare_mask: u32, 1744 ) -> &mut Self { 1745 self.validate_set_stencil_compare_mask(faces, compare_mask) 1746 .unwrap(); 1747 1748 unsafe { self.set_stencil_compare_mask_unchecked(faces, compare_mask) } 1749 } 1750 validate_set_stencil_compare_mask( &self, faces: StencilFaces, _compare_mask: u32, ) -> Result<(), SetDynamicStateError>1751 fn validate_set_stencil_compare_mask( 1752 &self, 1753 faces: StencilFaces, 1754 _compare_mask: u32, 1755 ) -> Result<(), SetDynamicStateError> { 1756 self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?; 1757 1758 // VUID-vkCmdSetStencilCompareMask-faceMask-parameter 1759 faces.validate_device(self.device())?; 1760 1761 let queue_family_properties = self.queue_family_properties(); 1762 1763 // VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool 1764 if !queue_family_properties 1765 .queue_flags 1766 .intersects(QueueFlags::GRAPHICS) 1767 { 1768 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1769 } 1770 1771 Ok(()) 1772 } 1773 1774 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_stencil_compare_mask_unchecked( &mut self, faces: StencilFaces, compare_mask: u32, ) -> &mut Self1775 pub unsafe fn set_stencil_compare_mask_unchecked( 1776 &mut self, 1777 faces: StencilFaces, 1778 compare_mask: u32, 1779 ) -> &mut Self { 1780 let fns = self.device().fns(); 1781 (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle(), faces.into(), compare_mask); 1782 1783 let faces = ash::vk::StencilFaceFlags::from(faces); 1784 1785 if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { 1786 self.builder_state.stencil_compare_mask.front = Some(compare_mask); 1787 } 1788 1789 if faces.intersects(ash::vk::StencilFaceFlags::BACK) { 1790 self.builder_state.stencil_compare_mask.back = Some(compare_mask); 1791 } 1792 1793 self.next_command_index += 1; 1794 self 1795 } 1796 1797 /// Sets the dynamic stencil ops on one or both faces for future draw calls. 1798 /// 1799 /// # Panics 1800 /// 1801 /// - Panics if the queue family of the command buffer does not support graphics operations. 1802 /// - Panics if the device API version is less than 1.3 and the 1803 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 1804 /// not enabled on the device. 1805 /// - Panics if the currently bound graphics pipeline already contains this state internally. 1806 #[inline] set_stencil_op( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> &mut Self1807 pub fn set_stencil_op( 1808 &mut self, 1809 faces: StencilFaces, 1810 fail_op: StencilOp, 1811 pass_op: StencilOp, 1812 depth_fail_op: StencilOp, 1813 compare_op: CompareOp, 1814 ) -> &mut Self { 1815 self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op) 1816 .unwrap(); 1817 1818 unsafe { self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op) } 1819 } 1820 validate_set_stencil_op( &self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError>1821 fn validate_set_stencil_op( 1822 &self, 1823 faces: StencilFaces, 1824 fail_op: StencilOp, 1825 pass_op: StencilOp, 1826 depth_fail_op: StencilOp, 1827 compare_op: CompareOp, 1828 ) -> Result<(), SetDynamicStateError> { 1829 self.validate_pipeline_fixed_state(DynamicState::StencilOp)?; 1830 1831 // VUID-vkCmdSetStencilOp-faceMask-parameter 1832 faces.validate_device(self.device())?; 1833 1834 // VUID-vkCmdSetStencilOp-failOp-parameter 1835 fail_op.validate_device(self.device())?; 1836 1837 // VUID-vkCmdSetStencilOp-passOp-parameter 1838 pass_op.validate_device(self.device())?; 1839 1840 // VUID-vkCmdSetStencilOp-depthFailOp-parameter 1841 depth_fail_op.validate_device(self.device())?; 1842 1843 // VUID-vkCmdSetStencilOp-compareOp-parameter 1844 compare_op.validate_device(self.device())?; 1845 1846 let queue_family_properties = self.queue_family_properties(); 1847 1848 // VUID-vkCmdSetStencilOp-commandBuffer-cmdpool 1849 if !queue_family_properties 1850 .queue_flags 1851 .intersects(QueueFlags::GRAPHICS) 1852 { 1853 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1854 } 1855 1856 // VUID-vkCmdSetStencilOp-None-03351 1857 if !(self.device().api_version() >= Version::V1_3 1858 || self.device().enabled_features().extended_dynamic_state) 1859 { 1860 return Err(SetDynamicStateError::RequirementNotMet { 1861 required_for: "`CommandBufferBuilder::set_stencil_op`", 1862 requires_one_of: RequiresOneOf { 1863 api_version: Some(Version::V1_3), 1864 features: &["extended_dynamic_state"], 1865 ..Default::default() 1866 }, 1867 }); 1868 } 1869 1870 Ok(()) 1871 } 1872 1873 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_stencil_op_unchecked( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> &mut Self1874 pub unsafe fn set_stencil_op_unchecked( 1875 &mut self, 1876 faces: StencilFaces, 1877 fail_op: StencilOp, 1878 pass_op: StencilOp, 1879 depth_fail_op: StencilOp, 1880 compare_op: CompareOp, 1881 ) -> &mut Self { 1882 let fns = self.device().fns(); 1883 1884 if self.device().api_version() >= Version::V1_3 { 1885 (fns.v1_3.cmd_set_stencil_op)( 1886 self.handle(), 1887 faces.into(), 1888 fail_op.into(), 1889 pass_op.into(), 1890 depth_fail_op.into(), 1891 compare_op.into(), 1892 ); 1893 } else { 1894 debug_assert!( 1895 self.device() 1896 .enabled_extensions() 1897 .ext_extended_dynamic_state 1898 ); 1899 (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)( 1900 self.handle(), 1901 faces.into(), 1902 fail_op.into(), 1903 pass_op.into(), 1904 depth_fail_op.into(), 1905 compare_op.into(), 1906 ); 1907 } 1908 1909 let faces = ash::vk::StencilFaceFlags::from(faces); 1910 1911 if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { 1912 self.builder_state.stencil_op.front = Some(StencilOps { 1913 fail_op, 1914 pass_op, 1915 depth_fail_op, 1916 compare_op, 1917 }); 1918 } 1919 1920 if faces.intersects(ash::vk::StencilFaceFlags::BACK) { 1921 self.builder_state.stencil_op.back = Some(StencilOps { 1922 fail_op, 1923 pass_op, 1924 depth_fail_op, 1925 compare_op, 1926 }); 1927 } 1928 1929 self.next_command_index += 1; 1930 self 1931 } 1932 1933 /// Sets the dynamic stencil reference on one or both faces for future draw calls. 1934 /// 1935 /// # Panics 1936 /// 1937 /// - Panics if the queue family of the command buffer does not support graphics operations. 1938 /// - Panics if the currently bound graphics pipeline already contains this state internally. set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self1939 pub fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self { 1940 self.validate_set_stencil_reference(faces, reference) 1941 .unwrap(); 1942 1943 unsafe { self.set_stencil_reference_unchecked(faces, reference) } 1944 } 1945 validate_set_stencil_reference( &self, faces: StencilFaces, _reference: u32, ) -> Result<(), SetDynamicStateError>1946 fn validate_set_stencil_reference( 1947 &self, 1948 faces: StencilFaces, 1949 _reference: u32, 1950 ) -> Result<(), SetDynamicStateError> { 1951 self.validate_pipeline_fixed_state(DynamicState::StencilReference)?; 1952 1953 // VUID-vkCmdSetStencilReference-faceMask-parameter 1954 faces.validate_device(self.device())?; 1955 1956 let queue_family_properties = self.queue_family_properties(); 1957 1958 // VUID-vkCmdSetStencilReference-commandBuffer-cmdpool 1959 if !queue_family_properties 1960 .queue_flags 1961 .intersects(QueueFlags::GRAPHICS) 1962 { 1963 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 1964 } 1965 1966 Ok(()) 1967 } 1968 1969 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_stencil_reference_unchecked( &mut self, faces: StencilFaces, reference: u32, ) -> &mut Self1970 pub unsafe fn set_stencil_reference_unchecked( 1971 &mut self, 1972 faces: StencilFaces, 1973 reference: u32, 1974 ) -> &mut Self { 1975 let fns = self.device().fns(); 1976 (fns.v1_0.cmd_set_stencil_reference)(self.handle(), faces.into(), reference); 1977 1978 let faces = ash::vk::StencilFaceFlags::from(faces); 1979 1980 if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { 1981 self.builder_state.stencil_reference.front = Some(reference); 1982 } 1983 1984 if faces.intersects(ash::vk::StencilFaceFlags::BACK) { 1985 self.builder_state.stencil_reference.back = Some(reference); 1986 } 1987 1988 self.next_command_index += 1; 1989 self 1990 } 1991 1992 /// Sets whether dynamic stencil testing is enabled for future draw calls. 1993 /// 1994 /// # Panics 1995 /// 1996 /// - Panics if the queue family of the command buffer does not support graphics operations. 1997 /// - Panics if the device API version is less than 1.3 and the 1998 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 1999 /// not enabled on the device. 2000 /// - Panics if the currently bound graphics pipeline already contains this state internally. 2001 #[inline] set_stencil_test_enable(&mut self, enable: bool) -> &mut Self2002 pub fn set_stencil_test_enable(&mut self, enable: bool) -> &mut Self { 2003 self.validate_set_stencil_test_enable(enable).unwrap(); 2004 2005 unsafe { self.set_stencil_test_enable_unchecked(enable) } 2006 } 2007 validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>2008 fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { 2009 self.validate_pipeline_fixed_state(DynamicState::StencilTestEnable)?; 2010 2011 let queue_family_properties = self.queue_family_properties(); 2012 2013 // VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool 2014 if !queue_family_properties 2015 .queue_flags 2016 .intersects(QueueFlags::GRAPHICS) 2017 { 2018 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 2019 } 2020 2021 // VUID-vkCmdSetStencilTestEnable-None-03350 2022 if !(self.device().api_version() >= Version::V1_3 2023 || self.device().enabled_features().extended_dynamic_state) 2024 { 2025 return Err(SetDynamicStateError::RequirementNotMet { 2026 required_for: "`CommandBufferBuilder::set_stencil_test_enable`", 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 Ok(()) 2036 } 2037 2038 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self2039 pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self { 2040 let fns = self.device().fns(); 2041 2042 if self.device().api_version() >= Version::V1_3 { 2043 (fns.v1_3.cmd_set_stencil_test_enable)(self.handle(), enable.into()); 2044 } else { 2045 debug_assert!( 2046 self.device() 2047 .enabled_extensions() 2048 .ext_extended_dynamic_state 2049 ); 2050 (fns.ext_extended_dynamic_state 2051 .cmd_set_stencil_test_enable_ext)(self.handle(), enable.into()); 2052 } 2053 2054 self.builder_state.stencil_test_enable = Some(enable); 2055 2056 self.next_command_index += 1; 2057 self 2058 } 2059 2060 /// Sets the dynamic stencil write mask on one or both faces for future draw calls. 2061 /// 2062 /// # Panics 2063 /// 2064 /// - Panics if the queue family of the command buffer does not support graphics operations. 2065 /// - Panics if the currently bound graphics pipeline already contains this state internally. set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self2066 pub fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self { 2067 self.validate_set_stencil_write_mask(faces, write_mask) 2068 .unwrap(); 2069 2070 unsafe { self.set_stencil_write_mask_unchecked(faces, write_mask) } 2071 } 2072 validate_set_stencil_write_mask( &self, faces: StencilFaces, _write_mask: u32, ) -> Result<(), SetDynamicStateError>2073 fn validate_set_stencil_write_mask( 2074 &self, 2075 faces: StencilFaces, 2076 _write_mask: u32, 2077 ) -> Result<(), SetDynamicStateError> { 2078 self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?; 2079 2080 // VUID-vkCmdSetStencilWriteMask-faceMask-parameter 2081 faces.validate_device(self.device())?; 2082 2083 let queue_family_properties = self.queue_family_properties(); 2084 2085 // VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool 2086 if !queue_family_properties 2087 .queue_flags 2088 .intersects(QueueFlags::GRAPHICS) 2089 { 2090 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 2091 } 2092 2093 Ok(()) 2094 } 2095 2096 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_stencil_write_mask_unchecked( &mut self, faces: StencilFaces, write_mask: u32, ) -> &mut Self2097 pub unsafe fn set_stencil_write_mask_unchecked( 2098 &mut self, 2099 faces: StencilFaces, 2100 write_mask: u32, 2101 ) -> &mut Self { 2102 let fns = self.device().fns(); 2103 (fns.v1_0.cmd_set_stencil_write_mask)(self.handle(), faces.into(), write_mask); 2104 2105 let faces = ash::vk::StencilFaceFlags::from(faces); 2106 2107 if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { 2108 self.builder_state.stencil_write_mask.front = Some(write_mask); 2109 } 2110 2111 if faces.intersects(ash::vk::StencilFaceFlags::BACK) { 2112 self.builder_state.stencil_write_mask.back = Some(write_mask); 2113 } 2114 2115 self.next_command_index += 1; 2116 self 2117 } 2118 2119 /// Sets the dynamic viewports for future draw calls. 2120 /// 2121 /// # Panics 2122 /// 2123 /// - Panics if the queue family of the command buffer does not support graphics operations. 2124 /// - Panics if the currently bound graphics pipeline already contains this state internally. 2125 /// - Panics if the highest viewport slot being set is greater than the 2126 /// [`max_viewports`](crate::device::Properties::max_viewports) device property. 2127 /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, 2128 /// panics if `first_viewport` is not 0, or if more than 1 viewport is provided. set_viewport( &mut self, first_viewport: u32, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2129 pub fn set_viewport( 2130 &mut self, 2131 first_viewport: u32, 2132 viewports: impl IntoIterator<Item = Viewport>, 2133 ) -> &mut Self { 2134 let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); 2135 self.validate_set_viewport(first_viewport, &viewports) 2136 .unwrap(); 2137 2138 unsafe { self.set_viewport_unchecked(first_viewport, viewports) } 2139 } 2140 validate_set_viewport( &self, first_viewport: u32, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError>2141 fn validate_set_viewport( 2142 &self, 2143 first_viewport: u32, 2144 viewports: &[Viewport], 2145 ) -> Result<(), SetDynamicStateError> { 2146 self.validate_pipeline_fixed_state(DynamicState::Viewport)?; 2147 2148 let queue_family_properties = self.queue_family_properties(); 2149 2150 // VUID-vkCmdSetViewport-commandBuffer-cmdpool 2151 if !queue_family_properties 2152 .queue_flags 2153 .intersects(QueueFlags::GRAPHICS) 2154 { 2155 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 2156 } 2157 2158 // VUID-vkCmdSetViewport-firstViewport-01223 2159 if first_viewport + viewports.len() as u32 2160 > self.device().physical_device().properties().max_viewports 2161 { 2162 return Err(SetDynamicStateError::MaxViewportsExceeded { 2163 provided: first_viewport + viewports.len() as u32, 2164 max: self.device().physical_device().properties().max_viewports, 2165 }); 2166 } 2167 2168 if !self.device().enabled_features().multi_viewport { 2169 // VUID-vkCmdSetViewport-firstViewport-01224 2170 if first_viewport != 0 { 2171 return Err(SetDynamicStateError::RequirementNotMet { 2172 required_for: "`first_scissors` is not `0`", 2173 requires_one_of: RequiresOneOf { 2174 features: &["multi_viewport"], 2175 ..Default::default() 2176 }, 2177 }); 2178 } 2179 2180 // VUID-vkCmdSetViewport-viewportCount-01225 2181 if viewports.len() > 1 { 2182 return Err(SetDynamicStateError::RequirementNotMet { 2183 required_for: "`viewports.len()` is greater than `1`", 2184 requires_one_of: RequiresOneOf { 2185 features: &["multi_viewport"], 2186 ..Default::default() 2187 }, 2188 }); 2189 } 2190 } 2191 2192 Ok(()) 2193 } 2194 2195 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_viewport_unchecked( &mut self, first_viewport: u32, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2196 pub unsafe fn set_viewport_unchecked( 2197 &mut self, 2198 first_viewport: u32, 2199 viewports: impl IntoIterator<Item = Viewport>, 2200 ) -> &mut Self { 2201 let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); 2202 2203 if viewports.is_empty() { 2204 return self; 2205 } 2206 2207 let viewports_vk = viewports 2208 .iter() 2209 .cloned() 2210 .map(ash::vk::Viewport::from) 2211 .collect::<SmallVec<[_; 2]>>(); 2212 2213 let fns = self.device().fns(); 2214 (fns.v1_0.cmd_set_viewport)( 2215 self.handle(), 2216 first_viewport, 2217 viewports_vk.len() as u32, 2218 viewports_vk.as_ptr(), 2219 ); 2220 2221 for (num, viewport) in viewports.iter().enumerate() { 2222 let num = num as u32 + first_viewport; 2223 self.builder_state.viewport.insert(num, viewport.clone()); 2224 } 2225 2226 self.next_command_index += 1; 2227 self 2228 } 2229 2230 /// Sets the dynamic viewports with count for future draw calls. 2231 /// 2232 /// # Panics 2233 /// 2234 /// - Panics if the queue family of the command buffer does not support graphics operations. 2235 /// - Panics if the device API version is less than 1.3 and the 2236 /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is 2237 /// not enabled on the device. 2238 /// - Panics if the currently bound graphics pipeline already contains this state internally. 2239 /// - Panics if the highest viewport slot being set is greater than the 2240 /// [`max_viewports`](crate::device::Properties::max_viewports) device property. 2241 /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, 2242 /// panics if more than 1 viewport is provided. 2243 #[inline] set_viewport_with_count( &mut self, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2244 pub fn set_viewport_with_count( 2245 &mut self, 2246 viewports: impl IntoIterator<Item = Viewport>, 2247 ) -> &mut Self { 2248 let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); 2249 self.validate_set_viewport_with_count(&viewports).unwrap(); 2250 2251 unsafe { self.set_viewport_with_count_unchecked(viewports) } 2252 } 2253 validate_set_viewport_with_count( &self, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError>2254 fn validate_set_viewport_with_count( 2255 &self, 2256 viewports: &[Viewport], 2257 ) -> Result<(), SetDynamicStateError> { 2258 self.validate_pipeline_fixed_state(DynamicState::ViewportWithCount)?; 2259 2260 let queue_family_properties = self.queue_family_properties(); 2261 2262 // VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool 2263 if !queue_family_properties 2264 .queue_flags 2265 .intersects(QueueFlags::GRAPHICS) 2266 { 2267 return Err(SetDynamicStateError::NotSupportedByQueueFamily); 2268 } 2269 2270 // VUID-vkCmdSetViewportWithCount-None-03393 2271 if !(self.device().api_version() >= Version::V1_3 2272 || self.device().enabled_features().extended_dynamic_state) 2273 { 2274 return Err(SetDynamicStateError::RequirementNotMet { 2275 required_for: "`CommandBufferBuilder::set_viewport_with_count`", 2276 requires_one_of: RequiresOneOf { 2277 api_version: Some(Version::V1_3), 2278 features: &["extended_dynamic_state"], 2279 ..Default::default() 2280 }, 2281 }); 2282 } 2283 2284 // VUID-vkCmdSetViewportWithCount-viewportCount-03394 2285 if viewports.len() as u32 > self.device().physical_device().properties().max_viewports { 2286 return Err(SetDynamicStateError::MaxViewportsExceeded { 2287 provided: viewports.len() as u32, 2288 max: self.device().physical_device().properties().max_viewports, 2289 }); 2290 } 2291 2292 // VUID-vkCmdSetViewportWithCount-viewportCount-03395 2293 if !self.device().enabled_features().multi_viewport && viewports.len() > 1 { 2294 return Err(SetDynamicStateError::RequirementNotMet { 2295 required_for: "`viewports.len()` is greater than `1`", 2296 requires_one_of: RequiresOneOf { 2297 features: &["multi_viewport"], 2298 ..Default::default() 2299 }, 2300 }); 2301 } 2302 2303 Ok(()) 2304 } 2305 2306 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] set_viewport_with_count_unchecked( &mut self, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2307 pub unsafe fn set_viewport_with_count_unchecked( 2308 &mut self, 2309 viewports: impl IntoIterator<Item = Viewport>, 2310 ) -> &mut Self { 2311 let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); 2312 2313 if viewports.is_empty() { 2314 return self; 2315 } 2316 2317 let viewports_vk = viewports 2318 .iter() 2319 .cloned() 2320 .map(ash::vk::Viewport::from) 2321 .collect::<SmallVec<[_; 2]>>(); 2322 2323 let fns = self.device().fns(); 2324 2325 if self.device().api_version() >= Version::V1_3 { 2326 (fns.v1_3.cmd_set_viewport_with_count)( 2327 self.handle(), 2328 viewports_vk.len() as u32, 2329 viewports_vk.as_ptr(), 2330 ); 2331 } else { 2332 debug_assert!( 2333 self.device() 2334 .enabled_extensions() 2335 .ext_extended_dynamic_state 2336 ); 2337 (fns.ext_extended_dynamic_state 2338 .cmd_set_viewport_with_count_ext)( 2339 self.handle(), 2340 viewports_vk.len() as u32, 2341 viewports_vk.as_ptr(), 2342 ); 2343 } 2344 2345 self.builder_state.viewport_with_count = Some(viewports); 2346 2347 self.next_command_index += 1; 2348 self 2349 } 2350 } 2351