mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
Add partial support for khr_fragment_shading_rate
(#2574)
* support `khr_fragment_shading_rate` * Add taskgraph `set_fragment_shading_rate` * Add `set_fragment_shading_rate` validation * Cleanup `FragmentShadingRateState` validation * Consolidate fragment_shading_rate validation * Add docs for `fragment_shading_rate` * Update vulkano-taskgraph/src/command_buffer/commands/dynamic_state.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * Format fragment_shading_rate validation messages * Apply suggestions from code review Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --------- Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
This commit is contained in:
parent
dc619148b0
commit
6981040486
@ -7,6 +7,7 @@ use vulkano::{
|
||||
pipeline::graphics::{
|
||||
color_blend::LogicOp,
|
||||
depth_stencil::{CompareOp, StencilFaces, StencilOp},
|
||||
fragment_shading_rate::FragmentShadingRateCombinerOp,
|
||||
input_assembly::PrimitiveTopology,
|
||||
rasterization::{ConservativeRasterizationMode, CullMode, FrontFace},
|
||||
vertex_input::{
|
||||
@ -772,4 +773,34 @@ impl RecordingCommandBuffer<'_> {
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the dynamic fragment shading rate for future draw calls.
|
||||
pub unsafe fn set_fragment_shading_rate(
|
||||
&mut self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> Result<&mut Self> {
|
||||
unsafe { Ok(self.set_fragment_shading_rate_unchecked(fragment_size, combiner_ops)) }
|
||||
}
|
||||
|
||||
pub unsafe fn set_fragment_shading_rate_unchecked(
|
||||
&mut self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> &mut Self {
|
||||
let fns = self.device().fns();
|
||||
let fragment_size = vk::Extent2D {
|
||||
width: fragment_size[0],
|
||||
height: fragment_size[1],
|
||||
};
|
||||
let combiner_ops = [combiner_ops[0].into(), combiner_ops[1].into()];
|
||||
unsafe {
|
||||
(fns.khr_fragment_shading_rate
|
||||
.cmd_set_fragment_shading_rate_khr)(
|
||||
self.handle(), &fragment_size, &combiner_ops
|
||||
)
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use crate::{
|
||||
graphics::{
|
||||
color_blend::LogicOp,
|
||||
depth_stencil::{CompareOp, StencilOps},
|
||||
fragment_shading_rate::FragmentShadingRateState,
|
||||
input_assembly::PrimitiveTopology,
|
||||
rasterization::{
|
||||
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
||||
@ -1331,6 +1332,7 @@ pub(in crate::command_buffer) struct CommandBufferBuilderState {
|
||||
pub(in crate::command_buffer) conservative_rasterization_mode:
|
||||
Option<ConservativeRasterizationMode>,
|
||||
pub(in crate::command_buffer) extra_primitive_overestimation_size: Option<f32>,
|
||||
pub(in crate::command_buffer) fragment_shading_rate: Option<FragmentShadingRateState>,
|
||||
|
||||
// Active queries
|
||||
pub(in crate::command_buffer) queries: HashMap<QueryType, QueryState>,
|
||||
@ -1362,7 +1364,7 @@ impl CommandBufferBuilderState {
|
||||
DynamicState::DepthWriteEnable => self.depth_write_enable = None,
|
||||
DynamicState::DiscardRectangle => self.discard_rectangle.clear(),
|
||||
// DynamicState::ExclusiveScissor => todo!(),
|
||||
// DynamicState::FragmentShadingRate => todo!(),
|
||||
DynamicState::FragmentShadingRate => self.fragment_shading_rate = None,
|
||||
DynamicState::FrontFace => self.front_face = None,
|
||||
DynamicState::LineStipple => self.line_stipple = None,
|
||||
DynamicState::LineWidth => self.line_width = None,
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
graphics::{
|
||||
color_blend::LogicOp,
|
||||
depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
|
||||
fragment_shading_rate::{FragmentShadingRateCombinerOp, FragmentShadingRateState},
|
||||
input_assembly::PrimitiveTopology,
|
||||
rasterization::{
|
||||
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
||||
@ -1280,6 +1281,54 @@ impl<L> RecordingCommandBuffer<L> {
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the dynamic fragment shading rate for future draw calls.
|
||||
#[inline]
|
||||
pub fn set_fragment_shading_rate(
|
||||
&mut self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> Result<&mut Self, Box<ValidationError>> {
|
||||
self.validate_set_fragment_shading_rate(fragment_size, combiner_ops)?;
|
||||
|
||||
unsafe { Ok(self.set_fragment_shading_rate_unchecked(fragment_size, combiner_ops)) }
|
||||
}
|
||||
|
||||
fn validate_set_fragment_shading_rate(
|
||||
&self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
self.inner
|
||||
.validate_set_fragment_shading_rate(fragment_size, combiner_ops)?;
|
||||
|
||||
self.validate_graphics_pipeline_fixed_state(DynamicState::FragmentShadingRate)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn set_fragment_shading_rate_unchecked(
|
||||
&mut self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> &mut Self {
|
||||
self.builder_state.fragment_shading_rate = Some(FragmentShadingRateState {
|
||||
fragment_size,
|
||||
combiner_ops,
|
||||
..FragmentShadingRateState::default()
|
||||
});
|
||||
|
||||
self.add_command(
|
||||
"set_fragment_shading_rate",
|
||||
Default::default(),
|
||||
move |out: &mut RawRecordingCommandBuffer| {
|
||||
out.set_fragment_shading_rate_unchecked(fragment_size, combiner_ops);
|
||||
},
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RawRecordingCommandBuffer {
|
||||
@ -3381,4 +3430,44 @@ impl RawRecordingCommandBuffer {
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn validate_set_fragment_shading_rate(
|
||||
&self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
FragmentShadingRateState {
|
||||
fragment_size,
|
||||
combiner_ops,
|
||||
..FragmentShadingRateState::default()
|
||||
}
|
||||
.validate(self.device())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn set_fragment_shading_rate_unchecked(
|
||||
&mut self,
|
||||
fragment_size: [u32; 2],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
) -> &mut Self {
|
||||
let fns = self.device().fns();
|
||||
|
||||
let fragment_size = ash::vk::Extent2D {
|
||||
width: fragment_size[0],
|
||||
height: fragment_size[1],
|
||||
};
|
||||
let combiner_ops: [ash::vk::FragmentShadingRateCombinerOpKHR; 2] =
|
||||
[combiner_ops[0].into(), combiner_ops[1].into()];
|
||||
|
||||
(fns.khr_fragment_shading_rate
|
||||
.cmd_set_fragment_shading_rate_khr)(
|
||||
self.handle(),
|
||||
&fragment_size,
|
||||
combiner_ops.as_ptr().cast(),
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -2633,7 +2633,25 @@ impl<L> RecordingCommandBuffer<L> {
|
||||
}
|
||||
}
|
||||
// DynamicState::ExclusiveScissor => todo!(),
|
||||
// DynamicState::FragmentShadingRate => todo!(),
|
||||
DynamicState::FragmentShadingRate => {
|
||||
if self.builder_state.fragment_shading_rate.is_none() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"the currently bound graphics pipeline requires the \
|
||||
`DynamicState::{:?}` dynamic state, but \
|
||||
this state was either not set, or it was overwritten by a \
|
||||
more recent `bind_pipeline_graphics` command",
|
||||
dynamic_state
|
||||
)
|
||||
.into(),
|
||||
vuids: vuids!(
|
||||
vuid_type,
|
||||
"VUID-vkCmdDrawIndexed-pipelineFragmentShadingRate-09238"
|
||||
),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
DynamicState::FrontFace => {
|
||||
if self.builder_state.front_face.is_none() {
|
||||
return Err(Box::new(ValidationError {
|
||||
|
208
vulkano/src/pipeline/graphics/fragment_shading_rate.rs
Normal file
208
vulkano/src/pipeline/graphics/fragment_shading_rate.rs
Normal file
@ -0,0 +1,208 @@
|
||||
//! Fragment shading rate introduces the ability to change the rate at which fragments are shaded.
|
||||
//!
|
||||
//! This feature is part of the [`khr_fragment_shading_rate`] device extension.
|
||||
//!
|
||||
//! The fragment shading rate can be controlled per-draw, per-primitive, and per-region:
|
||||
//! - Per-draw shading rate requires the [`pipeline_fragment_shading_rate`] feature to be enabled
|
||||
//! on the device, and the rate can be set in a graphics pipeline or dynamically via
|
||||
//! [`set_fragment_shading_rate`].
|
||||
//! - Per-primitive shading rate requires the [`primitive_fragment_shading_rate`] feature to be
|
||||
//! enabled on the device, and is set in the last active pre-rasterization shader stage.
|
||||
//! - Per-region shading rate requires the [`attachment_fragment_shading_rate`] feature to be
|
||||
//! enabled on the device and an additional specialised fragment shading rate image attachment.
|
||||
//!
|
||||
//! `vulkano` does not currently support per-region shading state.
|
||||
//!
|
||||
//! [`khr_fragment_shading_rate`]: crate::device::DeviceExtensions::khr_fragment_shading_rate
|
||||
//! [`pipeline_fragment_shading_rate`]: crate::device::DeviceFeatures::pipeline_fragment_shading_rate
|
||||
//! [`set_fragment_shading_rate`]: crate::command_buffer::AutoCommandBufferBuilder::set_fragment_shading_rate
|
||||
//! [`primitive_fragment_shading_rate`]: crate::device::DeviceFeatures::primitive_fragment_shading_rate
|
||||
//! [`attachment_fragment_shading_rate`]: crate::device::DeviceFeatures::attachment_fragment_shading_rate
|
||||
|
||||
use crate::{device::Device, macros::vulkan_enum, ValidationError};
|
||||
use ash::vk;
|
||||
|
||||
/// The state in a graphics pipeline describing the fragment shading rate.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FragmentShadingRateState {
|
||||
/// The pipeline fragment shading rate.
|
||||
///
|
||||
/// The default value is `[1, 1]`.
|
||||
pub fragment_size: [u32; 2],
|
||||
|
||||
/// Determines how the pipeline, primitive, and attachment shading rates are combined for
|
||||
/// fragments generated.
|
||||
///
|
||||
/// The default value is `[FragmentShadingRateCombinerOp::Keep; 2]`.
|
||||
pub combiner_ops: [FragmentShadingRateCombinerOp; 2],
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for FragmentShadingRateState {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
fragment_size: [1, 1],
|
||||
combiner_ops: [FragmentShadingRateCombinerOp::Keep; 2],
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentShadingRateState {
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
fragment_size,
|
||||
combiner_ops,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
let properties = device.physical_device().properties();
|
||||
let features = device.enabled_features();
|
||||
|
||||
if !matches!(fragment_size[0], 1 | 2 | 4) {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "fragment_size[0]".into(),
|
||||
problem: "`fragment_size[0]` must be 1, 2, or 4".into(),
|
||||
vuids: &[
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04494",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04496",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04498",
|
||||
],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !matches!(fragment_size[1], 1 | 2 | 4) {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "fragment_size[1]".into(),
|
||||
problem: "`fragment_size[1]` must be 1, 2, or 4".into(),
|
||||
vuids: &[
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04495",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04497",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04499",
|
||||
],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !features.pipeline_fragment_shading_rate {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "features.pipeline_fragment_shading_rate".into(),
|
||||
problem: "the `pipeline_fragment_shading_rate` feature must be enabled".into(),
|
||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04500"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
combiner_ops[0].validate_device(device).map_err(|err| {
|
||||
err.add_context("combiner_ops[0]")
|
||||
.set_vuids(&["VUID-VkGraphicsPipelineCreateInfo-pDynamicState-06567"])
|
||||
})?;
|
||||
|
||||
combiner_ops[1].validate_device(device).map_err(|err| {
|
||||
err.add_context("combiner_ops[1]")
|
||||
.set_vuids(&["VUID-VkGraphicsPipelineCreateInfo-pDynamicState-06568"])
|
||||
})?;
|
||||
|
||||
if !features.primitive_fragment_shading_rate
|
||||
&& combiner_ops[0] != FragmentShadingRateCombinerOp::Keep
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "combiner_ops[0]".into(),
|
||||
problem: "the `primitive_fragment_shading_rate` feature must be enabled if \
|
||||
`combiner_ops[0]` is not `FragmentShadingRateCombinerOp::Keep`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04501"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !features.attachment_fragment_shading_rate
|
||||
&& combiner_ops[1] != FragmentShadingRateCombinerOp::Keep
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "combiner_ops[1]".into(),
|
||||
problem: "the `attachment_fragment_shading_rate` feature must be enabled if \
|
||||
`combiner_ops[1]` is not `FragmentShadingRateCombinerOp::Keep`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04502"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(fragment_shading_rate_non_trivial_combiner_ops) =
|
||||
properties.fragment_shading_rate_non_trivial_combiner_ops
|
||||
{
|
||||
if !fragment_shading_rate_non_trivial_combiner_ops
|
||||
&& (!matches!(
|
||||
combiner_ops[0],
|
||||
FragmentShadingRateCombinerOp::Keep | FragmentShadingRateCombinerOp::Replace
|
||||
) || !matches!(
|
||||
combiner_ops[1],
|
||||
FragmentShadingRateCombinerOp::Keep | FragmentShadingRateCombinerOp::Replace
|
||||
))
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "combiner_ops[0]".into(),
|
||||
problem: "the `fragment_shading_rate_non_trivial_combiner_ops` feature must be \
|
||||
enabled if `combiner_ops[0]` or `combiner_ops[1]` is not \
|
||||
`FragmentShadingRateCombinerOp::Keep` or \
|
||||
`FragmentShadingRateCombinerOp::Replace`"
|
||||
.into(),
|
||||
vuids: &[
|
||||
"VUID-VkGraphicsPipelineCreateInfo-fragmentShadingRateNonTrivialCombinerOps-04506",
|
||||
],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn to_vk<'a>(&self) -> ash::vk::PipelineFragmentShadingRateStateCreateInfoKHR<'a> {
|
||||
let fragment_size = vk::Extent2D {
|
||||
width: self.fragment_size[0],
|
||||
height: self.fragment_size[1],
|
||||
};
|
||||
let combiner_ops: [ash::vk::FragmentShadingRateCombinerOpKHR; 2] =
|
||||
[self.combiner_ops[0].into(), self.combiner_ops[1].into()];
|
||||
|
||||
ash::vk::PipelineFragmentShadingRateStateCreateInfoKHR::default()
|
||||
.fragment_size(fragment_size)
|
||||
.combiner_ops(combiner_ops)
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
/// Control how fragment shading rates are combined.
|
||||
FragmentShadingRateCombinerOp = FragmentShadingRateCombinerOpKHR(i32);
|
||||
|
||||
/// Specifies a combiner operation of combine(Axy,Bxy) = Axy.
|
||||
Keep = KEEP,
|
||||
|
||||
/// Specifies a combiner operation of combine(Axy,Bxy) = Bxy.
|
||||
Replace = REPLACE,
|
||||
|
||||
/// Specifies a combiner operation of combine(Axy,Bxy) = min(Axy,Bxy).
|
||||
Min = MIN,
|
||||
|
||||
/// Specifies a combiner operation of combine(Axy,Bxy) = max(Axy,Bxy).
|
||||
Max = MAX,
|
||||
|
||||
/// Specifies a combiner operation of combine(Axy,Bxy) = Axy * Bxy.
|
||||
///
|
||||
/// See the vulkan specification for more information on how this operation is performed if `fragmentShadingRateStrictMultiplyCombiner` is `false`.
|
||||
Mul = MUL,
|
||||
}
|
||||
|
||||
impl Default for FragmentShadingRateCombinerOp {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::Keep
|
||||
}
|
||||
}
|
@ -114,6 +114,7 @@ use crate::{
|
||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject,
|
||||
};
|
||||
use ahash::{HashMap, HashSet};
|
||||
use fragment_shading_rate::FragmentShadingRateState;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
collections::hash_map::Entry, fmt::Debug, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc,
|
||||
@ -122,6 +123,7 @@ use std::{
|
||||
pub mod color_blend;
|
||||
pub mod depth_stencil;
|
||||
pub mod discard_rectangle;
|
||||
pub mod fragment_shading_rate;
|
||||
pub mod input_assembly;
|
||||
pub mod multisample;
|
||||
pub mod rasterization;
|
||||
@ -157,6 +159,7 @@ pub struct GraphicsPipeline {
|
||||
subpass: PipelineSubpassType,
|
||||
|
||||
discard_rectangle_state: Option<DiscardRectangleState>,
|
||||
fragment_shading_rate_state: Option<FragmentShadingRateState>,
|
||||
|
||||
descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
|
||||
num_used_descriptor_sets: u32,
|
||||
@ -272,6 +275,8 @@ impl GraphicsPipeline {
|
||||
|
||||
discard_rectangle_state,
|
||||
|
||||
fragment_shading_rate_state,
|
||||
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
|
||||
@ -409,6 +414,10 @@ impl GraphicsPipeline {
|
||||
fixed_state.extend([DynamicState::DiscardRectangle]);
|
||||
}
|
||||
|
||||
if fragment_shading_rate_state.is_some() {
|
||||
fixed_state.extend([DynamicState::FragmentShadingRate]);
|
||||
}
|
||||
|
||||
fixed_state.retain(|state| !dynamic_state.contains(state));
|
||||
|
||||
Arc::new(Self {
|
||||
@ -432,6 +441,7 @@ impl GraphicsPipeline {
|
||||
subpass: subpass.unwrap(),
|
||||
|
||||
discard_rectangle_state,
|
||||
fragment_shading_rate_state,
|
||||
|
||||
descriptor_binding_requirements,
|
||||
num_used_descriptor_sets,
|
||||
@ -531,6 +541,12 @@ impl GraphicsPipeline {
|
||||
self.discard_rectangle_state.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the fragment shading rate state used to create this pipeline.
|
||||
#[inline]
|
||||
pub fn fragment_shading_rate_state(&self) -> Option<&FragmentShadingRateState> {
|
||||
self.fragment_shading_rate_state.as_ref()
|
||||
}
|
||||
|
||||
/// If the pipeline has a fragment shader, returns the fragment tests stages used.
|
||||
#[inline]
|
||||
pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
|
||||
@ -723,6 +739,11 @@ pub struct GraphicsPipelineCreateInfo {
|
||||
/// The default value is `None`.
|
||||
pub discard_rectangle_state: Option<DiscardRectangleState>,
|
||||
|
||||
/// The fragment shading rate state.
|
||||
///
|
||||
/// The default value is `None`.
|
||||
pub fragment_shading_rate_state: Option<FragmentShadingRateState>,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
@ -749,6 +770,8 @@ impl GraphicsPipelineCreateInfo {
|
||||
base_pipeline: None,
|
||||
|
||||
discard_rectangle_state: None,
|
||||
fragment_shading_rate_state: None,
|
||||
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -775,6 +798,8 @@ impl GraphicsPipelineCreateInfo {
|
||||
ref base_pipeline,
|
||||
|
||||
ref discard_rectangle_state,
|
||||
ref fragment_shading_rate_state,
|
||||
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
@ -1205,6 +1230,37 @@ impl GraphicsPipelineCreateInfo {
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match (
|
||||
fragment_shading_rate_state.is_some(),
|
||||
need_pre_rasterization_shader_state,
|
||||
) {
|
||||
(true, false) => {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "the pipeline is not being created with \
|
||||
pre-rasterization state, but \
|
||||
`fragment_shading_rate_state` is `Some`"
|
||||
.into(),
|
||||
vuids: &[
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04494",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04495",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04496",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04497",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04498",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04499",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04500",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-06567",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-06568",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04501",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04502",
|
||||
"VUID-VkGraphicsPipelineCreateInfo-fragmentShadingRateNonTrivialCombinerOps-04506",
|
||||
],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
(false, true) => (),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
/*
|
||||
Validate shader stages individually
|
||||
*/
|
||||
@ -1485,6 +1541,23 @@ impl GraphicsPipelineCreateInfo {
|
||||
.map_err(|err| err.add_context("discard_rectangle_state"))?;
|
||||
}
|
||||
|
||||
if let Some(fragment_shading_rate_state) = fragment_shading_rate_state {
|
||||
if !device.enabled_extensions().khr_fragment_shading_rate {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "fragment_shading_rate_state".into(),
|
||||
problem: "is `Some`".into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
||||
"khr_fragment_shading_rate",
|
||||
)])]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
fragment_shading_rate_state
|
||||
.validate(device)
|
||||
.map_err(|err| err.add_context("fragment_shading_rate_state"))?;
|
||||
}
|
||||
|
||||
for dynamic_state in dynamic_state.iter().copied() {
|
||||
dynamic_state.validate_device(device).map_err(|err| {
|
||||
err.add_context("dynamic_state")
|
||||
@ -2287,6 +2360,8 @@ impl GraphicsPipelineCreateInfo {
|
||||
ref base_pipeline,
|
||||
|
||||
discard_rectangle_state: _,
|
||||
fragment_shading_rate_state: _,
|
||||
|
||||
_ne: _,
|
||||
} = self;
|
||||
let (render_pass_vk, subpass_vk) = match subpass {
|
||||
@ -2360,12 +2435,17 @@ impl GraphicsPipelineCreateInfo {
|
||||
let GraphicsPipelineCreateInfoExtensionsVk {
|
||||
discard_rectangle_state_vk,
|
||||
rendering_vk,
|
||||
fragment_shading_rate_vk,
|
||||
} = extensions_vk;
|
||||
|
||||
if let Some(next) = discard_rectangle_state_vk {
|
||||
val_vk = val_vk.push_next(next);
|
||||
}
|
||||
|
||||
if let Some(next) = fragment_shading_rate_vk {
|
||||
val_vk = val_vk.push_next(next);
|
||||
}
|
||||
|
||||
if let Some(next) = rendering_vk {
|
||||
val_vk = val_vk.push_next(next);
|
||||
}
|
||||
@ -2392,10 +2472,15 @@ impl GraphicsPipelineCreateInfo {
|
||||
.as_ref()
|
||||
.zip(rendering_fields1_vk.as_ref())
|
||||
.map(|(subpass, fields1_vk)| subpass.to_vk_rendering(fields1_vk));
|
||||
let fragment_shading_rate_vk = self
|
||||
.fragment_shading_rate_state
|
||||
.as_ref()
|
||||
.map(|fragment_shading_rate_state| fragment_shading_rate_state.to_vk());
|
||||
|
||||
GraphicsPipelineCreateInfoExtensionsVk {
|
||||
discard_rectangle_state_vk,
|
||||
rendering_vk,
|
||||
fragment_shading_rate_vk,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2608,6 +2693,8 @@ pub(crate) struct GraphicsPipelineCreateInfoExtensionsVk<'a> {
|
||||
pub(crate) discard_rectangle_state_vk:
|
||||
Option<ash::vk::PipelineDiscardRectangleStateCreateInfoEXT<'a>>,
|
||||
pub(crate) rendering_vk: Option<ash::vk::PipelineRenderingCreateInfo<'a>>,
|
||||
pub(crate) fragment_shading_rate_vk:
|
||||
Option<ash::vk::PipelineFragmentShadingRateStateCreateInfoKHR<'a>>,
|
||||
}
|
||||
|
||||
pub(crate) struct GraphicsPipelineCreateInfoFields1Vk<'a> {
|
||||
|
@ -588,12 +588,15 @@ vulkan_enum! {
|
||||
RequiresAllOf([DeviceExtension(nv_scissor_exclusive)]),
|
||||
]), */
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
/// The value of
|
||||
/// [`FragmentShadingRateState`](crate::pipeline::graphics::fragment_shading_rate::FragmentShadingRateState).
|
||||
///
|
||||
/// Set with
|
||||
/// [`set_fragment_shading_rate`](crate::command_buffer::RecordingCommandBuffer::set_fragment_shading_rate).
|
||||
FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR
|
||||
RequiresOneOf([
|
||||
RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]),
|
||||
]), */
|
||||
]),
|
||||
|
||||
/// The value of
|
||||
/// [`RasterizationState::line_stipple`](crate::pipeline::graphics::rasterization::RasterizationState::line_stipple).
|
||||
|
Loading…
Reference in New Issue
Block a user