// Copyright (c) 2022 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. use crate::{ command_buffer::{ allocator::CommandBufferAllocator, synced::{Command, SyncCommandBufferBuilder}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, }, device::{DeviceOwned, QueueFlags}, pipeline::{ graphics::{ color_blend::LogicOp, depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps}, input_assembly::PrimitiveTopology, rasterization::{CullMode, DepthBias, FrontFace, LineStipple}, viewport::{Scissor, Viewport}, }, DynamicState, }, RequirementNotMet, RequiresOneOf, Version, }; use parking_lot::Mutex; use smallvec::SmallVec; use std::{ error::Error, fmt::{Display, Error as FmtError, Formatter}, ops::RangeInclusive, }; /// # Commands to set dynamic state for pipelines. /// /// These commands require a queue with a pipeline type that uses the given state. impl AutoCommandBufferBuilder where A: CommandBufferAllocator, { // Helper function for dynamic state setting. fn validate_pipeline_fixed_state( &self, state: DynamicState, ) -> Result<(), SetDynamicStateError> { // VUID-vkCmdDispatch-None-02859 if self.state().pipeline_graphics().map_or(false, |pipeline| { matches!(pipeline.dynamic_state(state), Some(false)) }) { return Err(SetDynamicStateError::PipelineHasFixedState); } Ok(()) } /// Sets the dynamic blend constants for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self { self.validate_set_blend_constants(constants).unwrap(); unsafe { self.inner.set_blend_constants(constants); } self } fn validate_set_blend_constants( &self, _constants: [f32; 4], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::BlendConstants)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } Ok(()) } /// Sets whether dynamic color writes should be enabled for each attachment in the /// framebuffer. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the [`color_write_enable`](crate::device::Features::color_write_enable) /// feature is not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal /// - [`attachments.len()`](crate::pipeline::graphics::color_blend::ColorBlendState::attachments). pub fn set_color_write_enable(&mut self, enables: I) -> &mut Self where I: IntoIterator, I::IntoIter: ExactSizeIterator, { let enables = enables.into_iter(); self.validate_set_color_write_enable(&enables).unwrap(); unsafe { self.inner.set_color_write_enable(enables); } self } fn validate_set_color_write_enable( &self, enables: &impl ExactSizeIterator, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::ColorWriteEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetColorWriteEnableEXT-None-04803 if !self.device().enabled_features().color_write_enable { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_color_write_enable`", requires_one_of: RequiresOneOf { device_extensions: &["ext_color_write_enable"], ..Default::default() }, }); } if let Some(color_blend_state) = self .state() .pipeline_graphics() .and_then(|pipeline| pipeline.color_blend_state()) { // VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656 // Indirectly checked if enables.len() != color_blend_state.attachments.len() { return Err( SetDynamicStateError::PipelineColorBlendAttachmentCountMismatch { provided_count: enables.len() as u32, required_count: color_blend_state.attachments.len() as u32, }, ); } } Ok(()) } /// Sets the dynamic cull mode for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self { self.validate_set_cull_mode(cull_mode).unwrap(); unsafe { self.inner.set_cull_mode(cull_mode); } self } fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::CullMode)?; // VUID-vkCmdSetCullMode-cullMode-parameter cull_mode.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetCullMode-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetCullMode-None-03384 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_cull_mode`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic depth bias values for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - If the [`depth_bias_clamp`](crate::device::Features::depth_bias_clamp) /// feature is not enabled on the device, panics if `clamp` is not 0.0. pub fn set_depth_bias( &mut self, constant_factor: f32, clamp: f32, slope_factor: f32, ) -> &mut Self { self.validate_set_depth_bias(constant_factor, clamp, slope_factor) .unwrap(); unsafe { self.inner .set_depth_bias(constant_factor, clamp, slope_factor); } self } fn validate_set_depth_bias( &self, _constant_factor: f32, clamp: f32, _slope_factor: f32, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthBias)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthBias-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthBias-depthBiasClamp-00790 if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`clamp` is not `0.0`", requires_one_of: RequiresOneOf { features: &["depth_bias_clamp"], ..Default::default() }, }); } Ok(()) } /// Sets whether dynamic depth bias is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_depth_bias_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_depth_bias_enable(enable).unwrap(); unsafe { self.inner.set_depth_bias_enable(enable); } self } fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthBiasEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthBiasEnable-None-04872 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state2) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_bias_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state2"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic depth bounds for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - If the /// [`ext_depth_range_unrestricted`](crate::device::DeviceExtensions::ext_depth_range_unrestricted) /// device extension is not enabled, panics if the start and end of `bounds` are not between /// 0.0 and 1.0 inclusive. pub fn set_depth_bounds(&mut self, bounds: RangeInclusive) -> &mut Self { self.validate_set_depth_bounds(bounds.clone()).unwrap(); unsafe { self.inner.set_depth_bounds(bounds); } self } fn validate_set_depth_bounds( &self, bounds: RangeInclusive, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthBounds)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthBounds-minDepthBounds-00600 // VUID-vkCmdSetDepthBounds-maxDepthBounds-00601 if !self .device() .enabled_extensions() .ext_depth_range_unrestricted && !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end())) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`bounds` is not between `0.0` and `1.0` inclusive", requires_one_of: RequiresOneOf { device_extensions: &["ext_depth_range_unrestricted"], ..Default::default() }, }); } Ok(()) } /// Sets whether dynamic depth bounds testing is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_depth_bounds_test_enable(enable).unwrap(); unsafe { self.inner.set_depth_bounds_test_enable(enable); } self } fn validate_set_depth_bounds_test_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthBoundsTestEnable-None-03349 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_bounds_test_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic depth compare op for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self { self.validate_set_depth_compare_op(compare_op).unwrap(); unsafe { self.inner.set_depth_compare_op(compare_op); } self } fn validate_set_depth_compare_op( &self, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?; // VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter compare_op.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthCompareOp-None-03353 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_compare_op`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets whether dynamic depth testing is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_depth_test_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_depth_test_enable(enable).unwrap(); unsafe { self.inner.set_depth_test_enable(enable); } self } fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthTestEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthTestEnable-None-03352 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_test_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets whether dynamic depth write is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_depth_write_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_depth_write_enable(enable).unwrap(); unsafe { self.inner.set_depth_write_enable(enable); } self } fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DepthWriteEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetDepthWriteEnable-None-03354 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_write_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic discard rectangles for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the /// [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles) /// extension is not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if the highest discard rectangle slot being set is greater than the /// [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) device /// property. pub fn set_discard_rectangle( &mut self, first_rectangle: u32, rectangles: impl IntoIterator, ) -> &mut Self { let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect(); self.validate_set_discard_rectangle(first_rectangle, &rectangles) .unwrap(); unsafe { self.inner .set_discard_rectangle(first_rectangle, rectangles); } self } fn validate_set_discard_rectangle( &self, first_rectangle: u32, rectangles: &[Scissor], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::DiscardRectangle)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } if self.device().enabled_extensions().ext_discard_rectangles { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_discard_rectangle`", requires_one_of: RequiresOneOf { device_extensions: &["ext_discard_rectangles"], ..Default::default() }, }); } // VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585 if first_rectangle + rectangles.len() as u32 > self .device() .physical_device() .properties() .max_discard_rectangles .unwrap() { return Err(SetDynamicStateError::MaxDiscardRectanglesExceeded { provided: first_rectangle + rectangles.len() as u32, max: self .device() .physical_device() .properties() .max_discard_rectangles .unwrap(), }); } Ok(()) } /// Sets the dynamic front face for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_front_face(&mut self, face: FrontFace) -> &mut Self { self.validate_set_front_face(face).unwrap(); unsafe { self.inner.set_front_face(face); } self } fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::FrontFace)?; // VUID-vkCmdSetFrontFace-frontFace-parameter face.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetFrontFace-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetFrontFace-None-03383 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_front_face`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic line stipple values for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization) /// extension is not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if `factor` is not between 1 and 256 inclusive. pub fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self { self.validate_set_line_stipple(factor, pattern).unwrap(); unsafe { self.inner.set_line_stipple(factor, pattern); } self } fn validate_set_line_stipple( &self, factor: u32, _pattern: u16, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::LineStipple)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } if !self.device().enabled_extensions().ext_line_rasterization { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_line_stipple`", requires_one_of: RequiresOneOf { device_extensions: &["ext_line_rasterization"], ..Default::default() }, }); } // VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776 if !(1..=256).contains(&factor) { return Err(SetDynamicStateError::FactorOutOfRange); } Ok(()) } /// Sets the dynamic line width for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - If the [`wide_lines`](crate::device::Features::wide_lines) feature is not enabled, panics /// if `line_width` is not 1.0. pub fn set_line_width(&mut self, line_width: f32) -> &mut Self { self.validate_set_line_width(line_width).unwrap(); unsafe { self.inner.set_line_width(line_width); } self } fn validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::LineWidth)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetLineWidth-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetLineWidth-lineWidth-00788 if !self.device().enabled_features().wide_lines && line_width != 1.0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`line_width` is not `1.0`", requires_one_of: RequiresOneOf { features: &["wide_lines"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic logic op for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op) /// feature is not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self { self.validate_set_logic_op(logic_op).unwrap(); unsafe { self.inner.set_logic_op(logic_op); } self } fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::LogicOp)?; // VUID-vkCmdSetLogicOpEXT-logicOp-parameter logic_op.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetLogicOpEXT-None-04867 if !self .device() .enabled_features() .extended_dynamic_state2_logic_op { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_logic_op`", requires_one_of: RequiresOneOf { features: &["extended_dynamic_state2_logic_op"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic number of patch control points for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points) /// feature is not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if `num` is 0. /// - Panics if `num` is greater than the /// [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size) /// property of the device. pub fn set_patch_control_points(&mut self, num: u32) -> &mut Self { self.validate_set_patch_control_points(num).unwrap(); unsafe { self.inner.set_patch_control_points(num); } self } fn validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::PatchControlPoints)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetPatchControlPointsEXT-None-04873 if !self .device() .enabled_features() .extended_dynamic_state2_patch_control_points { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_patch_control_points`", requires_one_of: RequiresOneOf { features: &["extended_dynamic_state2_patch_control_points"], ..Default::default() }, }); } // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874 assert!(num > 0, "num must be greater than 0"); // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874 if num > self .device() .physical_device() .properties() .max_tessellation_patch_size { return Err(SetDynamicStateError::MaxTessellationPatchSizeExceeded { provided: num, max: self .device() .physical_device() .properties() .max_tessellation_patch_size, }); } Ok(()) } /// Sets whether dynamic primitive restart is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_primitive_restart_enable(enable).unwrap(); unsafe { self.inner.set_primitive_restart_enable(enable); } self } fn validate_set_primitive_restart_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetPrimitiveRestartEnable-None-04866 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state2) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_primitive_restart_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state2"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic primitive topology for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - If the [`geometry_shader`](crate::device::Features::geometry_shader) feature is not /// enabled, panics if `topology` is a `WithAdjacency` topology. /// - If the [`tessellation_shader`](crate::device::Features::tessellation_shader) feature is /// not enabled, panics if `topology` is `PatchList`. pub fn set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self { self.validate_set_primitive_topology(topology).unwrap(); unsafe { self.inner.set_primitive_topology(topology); } self } fn validate_set_primitive_topology( &self, topology: PrimitiveTopology, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?; // VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter topology.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetPrimitiveTopology-None-03347 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_primitive_topology`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } // VUID? // Since these requirements exist for fixed state when creating the pipeline, // I assume they exist for dynamic state as well. match topology { PrimitiveTopology::TriangleFan => { if self.device().enabled_extensions().khr_portability_subset && !self.device().enabled_features().triangle_fans { return Err(SetDynamicStateError::RequirementNotMet { required_for: "this device is a portability subset device, and `topology` \ is `PrimitiveTopology::TriangleFan`", requires_one_of: RequiresOneOf { features: &["triangle_fans"], ..Default::default() }, }); } } PrimitiveTopology::LineListWithAdjacency | PrimitiveTopology::LineStripWithAdjacency | PrimitiveTopology::TriangleListWithAdjacency | PrimitiveTopology::TriangleStripWithAdjacency => { if !self.device().enabled_features().geometry_shader { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`", requires_one_of: RequiresOneOf { features: &["geometry_shader"], ..Default::default() }, }); } } PrimitiveTopology::PatchList => { if !self.device().enabled_features().tessellation_shader { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`topology` is `PrimitiveTopology::PatchList`", requires_one_of: RequiresOneOf { features: &["tessellation_shader"], ..Default::default() }, }); } } _ => (), } Ok(()) } /// Sets whether dynamic rasterizer discard is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_rasterizer_discard_enable(enable).unwrap(); unsafe { self.inner.set_rasterizer_discard_enable(enable); } self } fn validate_set_rasterizer_discard_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetRasterizerDiscardEnable-None-04871 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state2) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_rasterizer_discard_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state2"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic scissors for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if the highest scissor slot being set is greater than the /// [`max_viewports`](crate::device::Properties::max_viewports) device property. /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, /// panics if `first_scissor` is not 0, or if more than 1 scissor is provided. pub fn set_scissor( &mut self, first_scissor: u32, scissors: impl IntoIterator, ) -> &mut Self { let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); self.validate_set_scissor(first_scissor, &scissors).unwrap(); unsafe { self.inner.set_scissor(first_scissor, scissors); } self } fn validate_set_scissor( &self, first_scissor: u32, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::Scissor)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetScissor-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetScissor-firstScissor-00592 if first_scissor + scissors.len() as u32 > self.device().physical_device().properties().max_viewports { return Err(SetDynamicStateError::MaxViewportsExceeded { provided: first_scissor + scissors.len() as u32, max: self.device().physical_device().properties().max_viewports, }); } if !self.device().enabled_features().multi_viewport { // VUID-vkCmdSetScissor-firstScissor-00593 if first_scissor != 0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`first_scissor` is not `0`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } // VUID-vkCmdSetScissor-scissorCount-00594 if scissors.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`scissors.len()` is greater than `1`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } } Ok(()) } /// Sets the dynamic scissors with count for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if the highest scissor slot being set is greater than the /// [`max_viewports`](crate::device::Properties::max_viewports) device property. /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, /// panics if more than 1 scissor is provided. pub fn set_scissor_with_count( &mut self, scissors: impl IntoIterator, ) -> &mut Self { let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); self.validate_set_scissor_with_count(&scissors).unwrap(); unsafe { self.inner.set_scissor_with_count(scissors); } self } fn validate_set_scissor_with_count( &self, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::ScissorWithCount)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetScissorWithCount-None-03396 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_scissor_with_count`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } // VUID-vkCmdSetScissorWithCount-scissorCount-03397 if scissors.len() as u32 > self.device().physical_device().properties().max_viewports { return Err(SetDynamicStateError::MaxViewportsExceeded { provided: scissors.len() as u32, max: self.device().physical_device().properties().max_viewports, }); } // VUID-vkCmdSetScissorWithCount-scissorCount-03398 if !self.device().enabled_features().multi_viewport && scissors.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`scissors.len()` is greater than `1`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic stencil compare mask on one or both faces for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_stencil_compare_mask( &mut self, faces: StencilFaces, compare_mask: u32, ) -> &mut Self { self.validate_set_stencil_compare_mask(faces, compare_mask) .unwrap(); unsafe { self.inner.set_stencil_compare_mask(faces, compare_mask); } self } fn validate_set_stencil_compare_mask( &self, faces: StencilFaces, _compare_mask: u32, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?; // VUID-vkCmdSetStencilCompareMask-faceMask-parameter faces.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } Ok(()) } /// Sets the dynamic stencil ops on one or both faces for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_stencil_op( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> &mut Self { self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op) .unwrap(); unsafe { self.inner .set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op); } self } fn validate_set_stencil_op( &self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::StencilOp)?; // VUID-vkCmdSetStencilOp-faceMask-parameter faces.validate_device(self.device())?; // VUID-vkCmdSetStencilOp-failOp-parameter fail_op.validate_device(self.device())?; // VUID-vkCmdSetStencilOp-passOp-parameter pass_op.validate_device(self.device())?; // VUID-vkCmdSetStencilOp-depthFailOp-parameter depth_fail_op.validate_device(self.device())?; // VUID-vkCmdSetStencilOp-compareOp-parameter compare_op.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetStencilOp-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetStencilOp-None-03351 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_stencil_op`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic stencil reference on one or both faces for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self { self.validate_set_stencil_reference(faces, reference) .unwrap(); unsafe { self.inner.set_stencil_reference(faces, reference); } self } fn validate_set_stencil_reference( &self, faces: StencilFaces, _reference: u32, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::StencilReference)?; // VUID-vkCmdSetStencilReference-faceMask-parameter faces.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetStencilReference-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } Ok(()) } /// Sets whether dynamic stencil testing is enabled for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_stencil_test_enable(&mut self, enable: bool) -> &mut Self { self.validate_set_stencil_test_enable(enable).unwrap(); unsafe { self.inner.set_stencil_test_enable(enable); } self } fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::StencilTestEnable)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetStencilTestEnable-None-03350 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_stencil_test_enable`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } Ok(()) } /// Sets the dynamic stencil write mask on one or both faces for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. pub fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self { self.validate_set_stencil_write_mask(faces, write_mask) .unwrap(); unsafe { self.inner.set_stencil_write_mask(faces, write_mask); } self } fn validate_set_stencil_write_mask( &self, faces: StencilFaces, _write_mask: u32, ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?; // VUID-vkCmdSetStencilWriteMask-faceMask-parameter faces.validate_device(self.device())?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } Ok(()) } /// Sets the dynamic viewports for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if the highest viewport slot being set is greater than the /// [`max_viewports`](crate::device::Properties::max_viewports) device property. /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, /// panics if `first_viewport` is not 0, or if more than 1 viewport is provided. pub fn set_viewport( &mut self, first_viewport: u32, viewports: impl IntoIterator, ) -> &mut Self { let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); self.validate_set_viewport(first_viewport, &viewports) .unwrap(); unsafe { self.inner.set_viewport(first_viewport, viewports); } self } fn validate_set_viewport( &self, first_viewport: u32, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::Viewport)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetViewport-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetViewport-firstViewport-01223 if first_viewport + viewports.len() as u32 > self.device().physical_device().properties().max_viewports { return Err(SetDynamicStateError::MaxViewportsExceeded { provided: first_viewport + viewports.len() as u32, max: self.device().physical_device().properties().max_viewports, }); } if !self.device().enabled_features().multi_viewport { // VUID-vkCmdSetViewport-firstViewport-01224 if first_viewport != 0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`first_scissors` is not `0`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } // VUID-vkCmdSetViewport-viewportCount-01225 if viewports.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`viewports.len()` is greater than `1`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } } Ok(()) } /// Sets the dynamic viewports with count for future draw calls. /// /// # Panics /// /// - Panics if the queue family of the command buffer does not support graphics operations. /// - Panics if the device API version is less than 1.3 and the /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is /// not enabled on the device. /// - Panics if the currently bound graphics pipeline already contains this state internally. /// - Panics if the highest viewport slot being set is greater than the /// [`max_viewports`](crate::device::Properties::max_viewports) device property. /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled, /// panics if more than 1 viewport is provided. pub fn set_viewport_with_count( &mut self, viewports: impl IntoIterator, ) -> &mut Self { let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); self.validate_set_viewport_with_count(&viewports).unwrap(); unsafe { self.inner.set_viewport_with_count(viewports); } self } fn validate_set_viewport_with_count( &self, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError> { self.validate_pipeline_fixed_state(DynamicState::ViewportWithCount)?; let queue_family_properties = self.queue_family_properties(); // VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool if !queue_family_properties .queue_flags .intersects(QueueFlags::GRAPHICS) { return Err(SetDynamicStateError::NotSupportedByQueueFamily); } // VUID-vkCmdSetViewportWithCount-None-03393 if !(self.device().api_version() >= Version::V1_3 || self.device().enabled_features().extended_dynamic_state) { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_viewport_with_count`", requires_one_of: RequiresOneOf { api_version: Some(Version::V1_3), features: &["extended_dynamic_state"], ..Default::default() }, }); } // VUID-vkCmdSetViewportWithCount-viewportCount-03394 if viewports.len() as u32 > self.device().physical_device().properties().max_viewports { return Err(SetDynamicStateError::MaxViewportsExceeded { provided: viewports.len() as u32, max: self.device().physical_device().properties().max_viewports, }); } // VUID-vkCmdSetViewportWithCount-viewportCount-03395 if !self.device().enabled_features().multi_viewport && viewports.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`viewports.len()` is greater than `1`", requires_one_of: RequiresOneOf { features: &["multi_viewport"], ..Default::default() }, }); } Ok(()) } } impl SyncCommandBufferBuilder { /// Calls `vkCmdSetBlendConstants` on the builder. #[inline] pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) { struct Cmd { constants: [f32; 4], } impl Command for Cmd { fn name(&self) -> &'static str { "set_blend_constants" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_blend_constants(self.constants); } } self.commands.push(Box::new(Cmd { constants })); self.current_state.blend_constants = Some(constants); } /// Calls `vkCmdSetColorWriteEnableEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_color_write_enable(&mut self, enables: impl IntoIterator) { struct Cmd { enables: Mutex>, } impl Command for Cmd where I: IntoIterator + Send + Sync, { fn name(&self) -> &'static str { "set_color_write_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_color_write_enable(self.enables.lock().take().unwrap()); } } let enables: SmallVec<[bool; 4]> = enables.into_iter().collect(); self.current_state.color_write_enable = Some(enables.clone()); self.commands.push(Box::new(Cmd { enables: Mutex::new(Some(enables)), })); } /// Calls `vkCmdSetCullModeEXT` on the builder. #[inline] pub unsafe fn set_cull_mode(&mut self, cull_mode: CullMode) { struct Cmd { cull_mode: CullMode, } impl Command for Cmd { fn name(&self) -> &'static str { "set_cull_mode" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_cull_mode(self.cull_mode); } } self.commands.push(Box::new(Cmd { cull_mode })); self.current_state.cull_mode = Some(cull_mode); } /// Calls `vkCmdSetDepthBias` on the builder. #[inline] pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) { struct Cmd { constant_factor: f32, clamp: f32, slope_factor: f32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_bias" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_bias(self.constant_factor, self.clamp, self.slope_factor); } } self.commands.push(Box::new(Cmd { constant_factor, clamp, slope_factor, })); self.current_state.depth_bias = Some(DepthBias { constant_factor, clamp, slope_factor, }); } /// Calls `vkCmdSetDepthBiasEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_bias_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_bias_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_bias_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.depth_bias_enable = Some(enable); } /// Calls `vkCmdSetDepthBounds` on the builder. #[inline] pub unsafe fn set_depth_bounds(&mut self, bounds: RangeInclusive) { struct Cmd { bounds: RangeInclusive, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_bounds" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_bounds(self.bounds.clone()); } } self.commands.push(Box::new(Cmd { bounds: bounds.clone(), })); self.current_state.depth_bounds = Some(bounds); } /// Calls `vkCmdSetDepthBoundsTestEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_bounds_test_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_bounds_test_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_bounds_test_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.depth_bounds_test_enable = Some(enable); } /// Calls `vkCmdSetDepthCompareOpEXT` on the builder. #[inline] pub unsafe fn set_depth_compare_op(&mut self, compare_op: CompareOp) { struct Cmd { compare_op: CompareOp, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_compare_op" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_compare_op(self.compare_op); } } self.commands.push(Box::new(Cmd { compare_op })); self.current_state.depth_compare_op = Some(compare_op); } /// Calls `vkCmdSetDepthTestEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_test_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_test_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_test_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.depth_test_enable = Some(enable); } /// Calls `vkCmdSetDepthWriteEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_write_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_depth_write_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_depth_write_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.depth_write_enable = Some(enable); } /// Calls `vkCmdSetDiscardRectangle` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_discard_rectangle( &mut self, first_rectangle: u32, rectangles: impl IntoIterator, ) { struct Cmd { first_rectangle: u32, rectangles: Mutex>, } impl Command for Cmd { fn name(&self) -> &'static str { "set_discard_rectangle" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_discard_rectangle(self.first_rectangle, self.rectangles.lock().drain(..)); } } let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect(); for (num, rectangle) in rectangles.iter().enumerate() { let num = num as u32 + first_rectangle; self.current_state.discard_rectangle.insert(num, *rectangle); } self.commands.push(Box::new(Cmd { first_rectangle, rectangles: Mutex::new(rectangles), })); } /// Calls `vkCmdSetFrontFaceEXT` on the builder. #[inline] pub unsafe fn set_front_face(&mut self, face: FrontFace) { struct Cmd { face: FrontFace, } impl Command for Cmd { fn name(&self) -> &'static str { "set_front_face" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_front_face(self.face); } } self.commands.push(Box::new(Cmd { face })); self.current_state.front_face = Some(face); } /// Calls `vkCmdSetLineStippleEXT` on the builder. #[inline] pub unsafe fn set_line_stipple(&mut self, factor: u32, pattern: u16) { struct Cmd { factor: u32, pattern: u16, } impl Command for Cmd { fn name(&self) -> &'static str { "set_line_stipple" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_line_stipple(self.factor, self.pattern); } } self.commands.push(Box::new(Cmd { factor, pattern })); self.current_state.line_stipple = Some(LineStipple { factor, pattern }); } /// Calls `vkCmdSetLineWidth` on the builder. #[inline] pub unsafe fn set_line_width(&mut self, line_width: f32) { struct Cmd { line_width: f32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_line_width" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_line_width(self.line_width); } } self.commands.push(Box::new(Cmd { line_width })); self.current_state.line_width = Some(line_width); } /// Calls `vkCmdSetLogicOpEXT` on the builder. #[inline] pub unsafe fn set_logic_op(&mut self, logic_op: LogicOp) { struct Cmd { logic_op: LogicOp, } impl Command for Cmd { fn name(&self) -> &'static str { "set_logic_op" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_logic_op(self.logic_op); } } self.commands.push(Box::new(Cmd { logic_op })); self.current_state.logic_op = Some(logic_op); } /// Calls `vkCmdSetPatchControlPointsEXT` on the builder. #[inline] pub unsafe fn set_patch_control_points(&mut self, num: u32) { struct Cmd { num: u32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_patch_control_points" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_patch_control_points(self.num); } } self.commands.push(Box::new(Cmd { num })); self.current_state.patch_control_points = Some(num); } /// Calls `vkCmdSetPrimitiveRestartEnableEXT` on the builder. #[inline] pub unsafe fn set_primitive_restart_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_primitive_restart_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_primitive_restart_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.primitive_restart_enable = Some(enable); } /// Calls `vkCmdSetPrimitiveTopologyEXT` on the builder. #[inline] pub unsafe fn set_primitive_topology(&mut self, topology: PrimitiveTopology) { struct Cmd { topology: PrimitiveTopology, } impl Command for Cmd { fn name(&self) -> &'static str { "set_primitive_topology" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_primitive_topology(self.topology); } } self.commands.push(Box::new(Cmd { topology })); self.current_state.primitive_topology = Some(topology); } /// Calls `vkCmdSetRasterizerDiscardEnableEXT` on the builder. #[inline] pub unsafe fn set_rasterizer_discard_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_rasterizer_discard_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_rasterizer_discard_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.rasterizer_discard_enable = Some(enable); } /// Calls `vkCmdSetStencilCompareMask` on the builder. #[inline] pub unsafe fn set_stencil_compare_mask(&mut self, faces: StencilFaces, compare_mask: u32) { struct Cmd { faces: StencilFaces, compare_mask: u32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_stencil_compare_mask" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_stencil_compare_mask(self.faces, self.compare_mask); } } self.commands.push(Box::new(Cmd { faces, compare_mask, })); let faces = ash::vk::StencilFaceFlags::from(faces); if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { self.current_state.stencil_compare_mask.front = Some(compare_mask); } if faces.intersects(ash::vk::StencilFaceFlags::BACK) { self.current_state.stencil_compare_mask.back = Some(compare_mask); } } /// Calls `vkCmdSetStencilOpEXT` on the builder. #[inline] pub unsafe fn set_stencil_op( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) { struct Cmd { faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, } impl Command for Cmd { fn name(&self) -> &'static str { "set_stencil_op" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_stencil_op( self.faces, self.fail_op, self.pass_op, self.depth_fail_op, self.compare_op, ); } } self.commands.push(Box::new(Cmd { faces, fail_op, pass_op, depth_fail_op, compare_op, })); let faces = ash::vk::StencilFaceFlags::from(faces); if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { self.current_state.stencil_op.front = Some(StencilOps { fail_op, pass_op, depth_fail_op, compare_op, }); } if faces.intersects(ash::vk::StencilFaceFlags::BACK) { self.current_state.stencil_op.back = Some(StencilOps { fail_op, pass_op, depth_fail_op, compare_op, }); } } /// Calls `vkCmdSetStencilReference` on the builder. #[inline] pub unsafe fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) { struct Cmd { faces: StencilFaces, reference: u32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_stencil_reference" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_stencil_reference(self.faces, self.reference); } } self.commands.push(Box::new(Cmd { faces, reference })); let faces = ash::vk::StencilFaceFlags::from(faces); if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { self.current_state.stencil_reference.front = Some(reference); } if faces.intersects(ash::vk::StencilFaceFlags::BACK) { self.current_state.stencil_reference.back = Some(reference); } } /// Calls `vkCmdSetStencilTestEnableEXT` on the builder. #[inline] pub unsafe fn set_stencil_test_enable(&mut self, enable: bool) { struct Cmd { enable: bool, } impl Command for Cmd { fn name(&self) -> &'static str { "set_stencil_test_enable" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_stencil_test_enable(self.enable); } } self.commands.push(Box::new(Cmd { enable })); self.current_state.stencil_test_enable = Some(enable); } /// Calls `vkCmdSetStencilWriteMask` on the builder. #[inline] pub unsafe fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) { struct Cmd { faces: StencilFaces, write_mask: u32, } impl Command for Cmd { fn name(&self) -> &'static str { "set_stencil_write_mask" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_stencil_write_mask(self.faces, self.write_mask); } } self.commands.push(Box::new(Cmd { faces, write_mask })); let faces = ash::vk::StencilFaceFlags::from(faces); if faces.intersects(ash::vk::StencilFaceFlags::FRONT) { self.current_state.stencil_write_mask.front = Some(write_mask); } if faces.intersects(ash::vk::StencilFaceFlags::BACK) { self.current_state.stencil_write_mask.back = Some(write_mask); } } /// Calls `vkCmdSetScissor` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_scissor( &mut self, first_scissor: u32, scissors: impl IntoIterator, ) { struct Cmd { first_scissor: u32, scissors: Mutex>, } impl Command for Cmd { fn name(&self) -> &'static str { "set_scissor" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_scissor(self.first_scissor, self.scissors.lock().drain(..)); } } let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); for (num, scissor) in scissors.iter().enumerate() { let num = num as u32 + first_scissor; self.current_state.scissor.insert(num, *scissor); } self.commands.push(Box::new(Cmd { first_scissor, scissors: Mutex::new(scissors), })); } /// Calls `vkCmdSetScissorWithCountEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_scissor_with_count(&mut self, scissors: impl IntoIterator) { struct Cmd { scissors: Mutex>, } impl Command for Cmd { fn name(&self) -> &'static str { "set_scissor_with_count" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_scissor_with_count(self.scissors.lock().drain(..)); } } let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect(); self.current_state.scissor_with_count = Some(scissors.clone()); self.commands.push(Box::new(Cmd { scissors: Mutex::new(scissors), })); } /// Calls `vkCmdSetViewport` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_viewport( &mut self, first_viewport: u32, viewports: impl IntoIterator, ) { struct Cmd { first_viewport: u32, viewports: Mutex>, } impl Command for Cmd { fn name(&self) -> &'static str { "set_viewport" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_viewport(self.first_viewport, self.viewports.lock().drain(..)); } } let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); for (num, viewport) in viewports.iter().enumerate() { let num = num as u32 + first_viewport; self.current_state.viewport.insert(num, viewport.clone()); } self.commands.push(Box::new(Cmd { first_viewport, viewports: Mutex::new(viewports), })); } /// Calls `vkCmdSetViewportWithCountEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_viewport_with_count( &mut self, viewports: impl IntoIterator, ) { struct Cmd { viewports: Mutex>, } impl Command for Cmd { fn name(&self) -> &'static str { "set_viewport_with_count" } unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { out.set_viewport_with_count(self.viewports.lock().drain(..)); } } let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect(); self.current_state.viewport_with_count = Some(viewports.clone()); self.commands.push(Box::new(Cmd { viewports: Mutex::new(viewports), })); } } impl UnsafeCommandBufferBuilder { /// Calls `vkCmdSetBlendConstants` on the builder. #[inline] pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) { let fns = self.device.fns(); (fns.v1_0.cmd_set_blend_constants)(self.handle, &constants); } /// Calls `vkCmdSetColorWriteEnableEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_color_write_enable(&mut self, enables: impl IntoIterator) { debug_assert!(self.device.enabled_extensions().ext_color_write_enable); let enables = enables .into_iter() .map(|v| v as ash::vk::Bool32) .collect::>(); if enables.is_empty() { return; } let fns = self.device.fns(); (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)( self.handle, enables.len() as u32, enables.as_ptr(), ); } /// Calls `vkCmdSetCullModeEXT` on the builder. #[inline] pub unsafe fn set_cull_mode(&mut self, cull_mode: CullMode) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_cull_mode)(self.handle, cull_mode.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle, cull_mode.into()); } } /// Calls `vkCmdSetDepthBias` on the builder. #[inline] pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) { let fns = self.device.fns(); (fns.v1_0.cmd_set_depth_bias)(self.handle, constant_factor, clamp, slope_factor); } /// Calls `vkCmdSetDepthBiasEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_bias_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_depth_bias_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2); (fns.ext_extended_dynamic_state2 .cmd_set_depth_bias_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetDepthBounds` on the builder. #[inline] pub unsafe fn set_depth_bounds(&mut self, bounds: RangeInclusive) { let fns = self.device.fns(); (fns.v1_0.cmd_set_depth_bounds)(self.handle, *bounds.start(), *bounds.end()); } /// Calls `vkCmdSetDepthBoundsTestEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_bounds_test_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_depth_bounds_test_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetDepthCompareOpEXT` on the builder. #[inline] pub unsafe fn set_depth_compare_op(&mut self, compare_op: CompareOp) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_depth_compare_op)(self.handle, compare_op.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)( self.handle, compare_op.into(), ); } } /// Calls `vkCmdSetDepthTestEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_test_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_depth_test_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)( self.handle, enable.into(), ); } } /// Calls `vkCmdSetDepthWriteEnableEXT` on the builder. #[inline] pub unsafe fn set_depth_write_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_depth_write_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_depth_write_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetDiscardRectangleEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_discard_rectangle( &mut self, first_rectangle: u32, rectangles: impl IntoIterator, ) { debug_assert!(self.device.enabled_extensions().ext_discard_rectangles); let rectangles = rectangles .into_iter() .map(|v| v.into()) .collect::>(); if rectangles.is_empty() { return; } debug_assert!( first_rectangle + rectangles.len() as u32 <= self .device .physical_device() .properties() .max_discard_rectangles .unwrap() ); let fns = self.device.fns(); (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)( self.handle, first_rectangle, rectangles.len() as u32, rectangles.as_ptr(), ); } /// Calls `vkCmdSetFrontFaceEXT` on the builder. #[inline] pub unsafe fn set_front_face(&mut self, face: FrontFace) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_front_face)(self.handle, face.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle, face.into()); } } /// Calls `vkCmdSetLineStippleEXT` on the builder. #[inline] pub unsafe fn set_line_stipple(&mut self, factor: u32, pattern: u16) { debug_assert!(self.device.enabled_extensions().ext_line_rasterization); let fns = self.device.fns(); (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle, factor, pattern); } /// Calls `vkCmdSetLineWidth` on the builder. #[inline] pub unsafe fn set_line_width(&mut self, line_width: f32) { let fns = self.device.fns(); (fns.v1_0.cmd_set_line_width)(self.handle, line_width); } /// Calls `vkCmdSetLogicOpEXT` on the builder. #[inline] pub unsafe fn set_logic_op(&mut self, logic_op: LogicOp) { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2); debug_assert!( self.device .enabled_features() .extended_dynamic_state2_logic_op ); let fns = self.device.fns(); (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle, logic_op.into()); } /// Calls `vkCmdSetPatchControlPointsEXT` on the builder. #[inline] pub unsafe fn set_patch_control_points(&mut self, num: u32) { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2); let fns = self.device.fns(); (fns.ext_extended_dynamic_state2 .cmd_set_patch_control_points_ext)(self.handle, num); } /// Calls `vkCmdSetPrimitiveRestartEnableEXT` on the builder. #[inline] pub unsafe fn set_primitive_restart_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2); (fns.ext_extended_dynamic_state2 .cmd_set_primitive_restart_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetPrimitiveTopologyEXT` on the builder. #[inline] pub unsafe fn set_primitive_topology(&mut self, topology: PrimitiveTopology) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_primitive_topology)(self.handle, topology.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_primitive_topology_ext)(self.handle, topology.into()); } } /// Calls `vkCmdSetRasterizerDiscardEnableEXT` on the builder. #[inline] pub unsafe fn set_rasterizer_discard_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2); (fns.ext_extended_dynamic_state2 .cmd_set_rasterizer_discard_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetStencilCompareMask` on the builder. #[inline] pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) { let fns = self.device.fns(); (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle, face_mask.into(), compare_mask); } /// Calls `vkCmdSetStencilOpEXT` on the builder. #[inline] pub unsafe fn set_stencil_op( &mut self, face_mask: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_stencil_op)( self.handle, face_mask.into(), fail_op.into(), pass_op.into(), depth_fail_op.into(), compare_op.into(), ); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)( self.handle, face_mask.into(), fail_op.into(), pass_op.into(), depth_fail_op.into(), compare_op.into(), ); } } /// Calls `vkCmdSetStencilReference` on the builder. #[inline] pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) { let fns = self.device.fns(); (fns.v1_0.cmd_set_stencil_reference)(self.handle, face_mask.into(), reference); } /// Calls `vkCmdSetStencilTestEnableEXT` on the builder. #[inline] pub unsafe fn set_stencil_test_enable(&mut self, enable: bool) { let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_stencil_test_enable)(self.handle, enable.into()); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_stencil_test_enable_ext)(self.handle, enable.into()); } } /// Calls `vkCmdSetStencilWriteMask` on the builder. #[inline] pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) { let fns = self.device.fns(); (fns.v1_0.cmd_set_stencil_write_mask)(self.handle, face_mask.into(), write_mask); } /// Calls `vkCmdSetScissor` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_scissor( &mut self, first_scissor: u32, scissors: impl IntoIterator, ) { let scissors = scissors .into_iter() .map(ash::vk::Rect2D::from) .collect::>(); if scissors.is_empty() { return; } let fns = self.device.fns(); (fns.v1_0.cmd_set_scissor)( self.handle, first_scissor, scissors.len() as u32, scissors.as_ptr(), ); } /// Calls `vkCmdSetScissorWithCountEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_scissor_with_count(&mut self, scissors: impl IntoIterator) { let scissors = scissors .into_iter() .map(ash::vk::Rect2D::from) .collect::>(); if scissors.is_empty() { return; } let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_scissor_with_count)( self.handle, scissors.len() as u32, scissors.as_ptr(), ); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_scissor_with_count_ext)( self.handle, scissors.len() as u32, scissors.as_ptr(), ); } } /// Calls `vkCmdSetViewport` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_viewport( &mut self, first_viewport: u32, viewports: impl IntoIterator, ) { let viewports = viewports .into_iter() .map(|v| v.into()) .collect::>(); if viewports.is_empty() { return; } let fns = self.device.fns(); (fns.v1_0.cmd_set_viewport)( self.handle, first_viewport, viewports.len() as u32, viewports.as_ptr(), ); } /// Calls `vkCmdSetViewportWithCountEXT` on the builder. /// /// If the list is empty then the command is automatically ignored. pub unsafe fn set_viewport_with_count( &mut self, viewports: impl IntoIterator, ) { let viewports = viewports .into_iter() .map(|v| v.into()) .collect::>(); if viewports.is_empty() { return; } let fns = self.device.fns(); if self.device.api_version() >= Version::V1_3 { (fns.v1_3.cmd_set_viewport_with_count)( self.handle, viewports.len() as u32, viewports.as_ptr(), ); } else { debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state); (fns.ext_extended_dynamic_state .cmd_set_viewport_with_count_ext)( self.handle, viewports.len() as u32, viewports.as_ptr(), ); } } } #[derive(Clone, Debug)] #[allow(dead_code)] pub(in super::super) enum SetDynamicStateError { RequirementNotMet { required_for: &'static str, requires_one_of: RequiresOneOf, }, /// The provided `factor` is not between 1 and 256 inclusive. FactorOutOfRange, /// The [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) /// limit has been exceeded. MaxDiscardRectanglesExceeded { provided: u32, max: u32 }, /// The [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size) /// limit has been exceeded. MaxTessellationPatchSizeExceeded { provided: u32, max: u32 }, /// The [`max_viewports`](crate::device::Properties::max_viewports) /// limit has been exceeded. MaxViewportsExceeded { provided: u32, max: u32 }, /// The queue family doesn't allow this operation. NotSupportedByQueueFamily, /// The provided item count is different from the number of attachments in the color blend /// state of the currently bound pipeline. PipelineColorBlendAttachmentCountMismatch { provided_count: u32, required_count: u32, }, /// The currently bound pipeline contains this state as internally fixed state, which cannot be /// overridden with dynamic state. PipelineHasFixedState, } impl Error for SetDynamicStateError {} impl Display for SetDynamicStateError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match self { Self::RequirementNotMet { required_for, requires_one_of, } => write!( f, "a requirement was not met for: {}; requires one of: {}", required_for, requires_one_of, ), Self::FactorOutOfRange => write!( f, "the provided `factor` is not between 1 and 256 inclusive", ), Self::MaxDiscardRectanglesExceeded { .. } => { write!(f, "the `max_discard_rectangles` limit has been exceeded") } Self::MaxTessellationPatchSizeExceeded { .. } => write!( f, "the `max_tessellation_patch_size` limit has been exceeded", ), Self::MaxViewportsExceeded { .. } => { write!(f, "the `max_viewports` limit has been exceeded") } Self::NotSupportedByQueueFamily => { write!(f, "the queue family doesn't allow this operation") } Self::PipelineColorBlendAttachmentCountMismatch { provided_count, required_count, } => write!( f, "the provided item count ({}) is different from the number of attachments in the \ color blend state of the currently bound pipeline ({})", provided_count, required_count, ), Self::PipelineHasFixedState => write!( f, "the currently bound pipeline contains this state as internally fixed state, which \ cannot be overridden with dynamic state", ), } } } impl From for SetDynamicStateError { fn from(err: RequirementNotMet) -> Self { Self::RequirementNotMet { required_for: err.required_for, requires_one_of: err.requires_one_of, } } }