mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +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::{
|
pipeline::graphics::{
|
||||||
color_blend::LogicOp,
|
color_blend::LogicOp,
|
||||||
depth_stencil::{CompareOp, StencilFaces, StencilOp},
|
depth_stencil::{CompareOp, StencilFaces, StencilOp},
|
||||||
|
fragment_shading_rate::FragmentShadingRateCombinerOp,
|
||||||
input_assembly::PrimitiveTopology,
|
input_assembly::PrimitiveTopology,
|
||||||
rasterization::{ConservativeRasterizationMode, CullMode, FrontFace},
|
rasterization::{ConservativeRasterizationMode, CullMode, FrontFace},
|
||||||
vertex_input::{
|
vertex_input::{
|
||||||
@ -772,4 +773,34 @@ impl RecordingCommandBuffer<'_> {
|
|||||||
|
|
||||||
self
|
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::{
|
graphics::{
|
||||||
color_blend::LogicOp,
|
color_blend::LogicOp,
|
||||||
depth_stencil::{CompareOp, StencilOps},
|
depth_stencil::{CompareOp, StencilOps},
|
||||||
|
fragment_shading_rate::FragmentShadingRateState,
|
||||||
input_assembly::PrimitiveTopology,
|
input_assembly::PrimitiveTopology,
|
||||||
rasterization::{
|
rasterization::{
|
||||||
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
||||||
@ -1331,6 +1332,7 @@ pub(in crate::command_buffer) struct CommandBufferBuilderState {
|
|||||||
pub(in crate::command_buffer) conservative_rasterization_mode:
|
pub(in crate::command_buffer) conservative_rasterization_mode:
|
||||||
Option<ConservativeRasterizationMode>,
|
Option<ConservativeRasterizationMode>,
|
||||||
pub(in crate::command_buffer) extra_primitive_overestimation_size: Option<f32>,
|
pub(in crate::command_buffer) extra_primitive_overestimation_size: Option<f32>,
|
||||||
|
pub(in crate::command_buffer) fragment_shading_rate: Option<FragmentShadingRateState>,
|
||||||
|
|
||||||
// Active queries
|
// Active queries
|
||||||
pub(in crate::command_buffer) queries: HashMap<QueryType, QueryState>,
|
pub(in crate::command_buffer) queries: HashMap<QueryType, QueryState>,
|
||||||
@ -1362,7 +1364,7 @@ impl CommandBufferBuilderState {
|
|||||||
DynamicState::DepthWriteEnable => self.depth_write_enable = None,
|
DynamicState::DepthWriteEnable => self.depth_write_enable = None,
|
||||||
DynamicState::DiscardRectangle => self.discard_rectangle.clear(),
|
DynamicState::DiscardRectangle => self.discard_rectangle.clear(),
|
||||||
// DynamicState::ExclusiveScissor => todo!(),
|
// DynamicState::ExclusiveScissor => todo!(),
|
||||||
// DynamicState::FragmentShadingRate => todo!(),
|
DynamicState::FragmentShadingRate => self.fragment_shading_rate = None,
|
||||||
DynamicState::FrontFace => self.front_face = None,
|
DynamicState::FrontFace => self.front_face = None,
|
||||||
DynamicState::LineStipple => self.line_stipple = None,
|
DynamicState::LineStipple => self.line_stipple = None,
|
||||||
DynamicState::LineWidth => self.line_width = None,
|
DynamicState::LineWidth => self.line_width = None,
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
graphics::{
|
graphics::{
|
||||||
color_blend::LogicOp,
|
color_blend::LogicOp,
|
||||||
depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
|
depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
|
||||||
|
fragment_shading_rate::{FragmentShadingRateCombinerOp, FragmentShadingRateState},
|
||||||
input_assembly::PrimitiveTopology,
|
input_assembly::PrimitiveTopology,
|
||||||
rasterization::{
|
rasterization::{
|
||||||
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
ConservativeRasterizationMode, CullMode, DepthBiasState, FrontFace, LineStipple,
|
||||||
@ -1280,6 +1281,54 @@ impl<L> RecordingCommandBuffer<L> {
|
|||||||
|
|
||||||
self
|
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 {
|
impl RawRecordingCommandBuffer {
|
||||||
@ -3381,4 +3430,44 @@ impl RawRecordingCommandBuffer {
|
|||||||
|
|
||||||
self
|
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::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 => {
|
DynamicState::FrontFace => {
|
||||||
if self.builder_state.front_face.is_none() {
|
if self.builder_state.front_face.is_none() {
|
||||||
return Err(Box::new(ValidationError {
|
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,
|
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject,
|
||||||
};
|
};
|
||||||
use ahash::{HashMap, HashSet};
|
use ahash::{HashMap, HashSet};
|
||||||
|
use fragment_shading_rate::FragmentShadingRateState;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
collections::hash_map::Entry, fmt::Debug, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc,
|
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 color_blend;
|
||||||
pub mod depth_stencil;
|
pub mod depth_stencil;
|
||||||
pub mod discard_rectangle;
|
pub mod discard_rectangle;
|
||||||
|
pub mod fragment_shading_rate;
|
||||||
pub mod input_assembly;
|
pub mod input_assembly;
|
||||||
pub mod multisample;
|
pub mod multisample;
|
||||||
pub mod rasterization;
|
pub mod rasterization;
|
||||||
@ -157,6 +159,7 @@ pub struct GraphicsPipeline {
|
|||||||
subpass: PipelineSubpassType,
|
subpass: PipelineSubpassType,
|
||||||
|
|
||||||
discard_rectangle_state: Option<DiscardRectangleState>,
|
discard_rectangle_state: Option<DiscardRectangleState>,
|
||||||
|
fragment_shading_rate_state: Option<FragmentShadingRateState>,
|
||||||
|
|
||||||
descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
|
descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
|
||||||
num_used_descriptor_sets: u32,
|
num_used_descriptor_sets: u32,
|
||||||
@ -272,6 +275,8 @@ impl GraphicsPipeline {
|
|||||||
|
|
||||||
discard_rectangle_state,
|
discard_rectangle_state,
|
||||||
|
|
||||||
|
fragment_shading_rate_state,
|
||||||
|
|
||||||
_ne: _,
|
_ne: _,
|
||||||
} = create_info;
|
} = create_info;
|
||||||
|
|
||||||
@ -409,6 +414,10 @@ impl GraphicsPipeline {
|
|||||||
fixed_state.extend([DynamicState::DiscardRectangle]);
|
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));
|
fixed_state.retain(|state| !dynamic_state.contains(state));
|
||||||
|
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
@ -432,6 +441,7 @@ impl GraphicsPipeline {
|
|||||||
subpass: subpass.unwrap(),
|
subpass: subpass.unwrap(),
|
||||||
|
|
||||||
discard_rectangle_state,
|
discard_rectangle_state,
|
||||||
|
fragment_shading_rate_state,
|
||||||
|
|
||||||
descriptor_binding_requirements,
|
descriptor_binding_requirements,
|
||||||
num_used_descriptor_sets,
|
num_used_descriptor_sets,
|
||||||
@ -531,6 +541,12 @@ impl GraphicsPipeline {
|
|||||||
self.discard_rectangle_state.as_ref()
|
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.
|
/// If the pipeline has a fragment shader, returns the fragment tests stages used.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
|
pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
|
||||||
@ -723,6 +739,11 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub discard_rectangle_state: Option<DiscardRectangleState>,
|
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,
|
pub _ne: crate::NonExhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,6 +770,8 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
base_pipeline: None,
|
base_pipeline: None,
|
||||||
|
|
||||||
discard_rectangle_state: None,
|
discard_rectangle_state: None,
|
||||||
|
fragment_shading_rate_state: None,
|
||||||
|
|
||||||
_ne: crate::NonExhaustive(()),
|
_ne: crate::NonExhaustive(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -775,6 +798,8 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
ref base_pipeline,
|
ref base_pipeline,
|
||||||
|
|
||||||
ref discard_rectangle_state,
|
ref discard_rectangle_state,
|
||||||
|
ref fragment_shading_rate_state,
|
||||||
|
|
||||||
_ne: _,
|
_ne: _,
|
||||||
} = self;
|
} = 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
|
Validate shader stages individually
|
||||||
*/
|
*/
|
||||||
@ -1485,6 +1541,23 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
.map_err(|err| err.add_context("discard_rectangle_state"))?;
|
.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() {
|
for dynamic_state in dynamic_state.iter().copied() {
|
||||||
dynamic_state.validate_device(device).map_err(|err| {
|
dynamic_state.validate_device(device).map_err(|err| {
|
||||||
err.add_context("dynamic_state")
|
err.add_context("dynamic_state")
|
||||||
@ -2287,6 +2360,8 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
ref base_pipeline,
|
ref base_pipeline,
|
||||||
|
|
||||||
discard_rectangle_state: _,
|
discard_rectangle_state: _,
|
||||||
|
fragment_shading_rate_state: _,
|
||||||
|
|
||||||
_ne: _,
|
_ne: _,
|
||||||
} = self;
|
} = self;
|
||||||
let (render_pass_vk, subpass_vk) = match subpass {
|
let (render_pass_vk, subpass_vk) = match subpass {
|
||||||
@ -2360,12 +2435,17 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
let GraphicsPipelineCreateInfoExtensionsVk {
|
let GraphicsPipelineCreateInfoExtensionsVk {
|
||||||
discard_rectangle_state_vk,
|
discard_rectangle_state_vk,
|
||||||
rendering_vk,
|
rendering_vk,
|
||||||
|
fragment_shading_rate_vk,
|
||||||
} = extensions_vk;
|
} = extensions_vk;
|
||||||
|
|
||||||
if let Some(next) = discard_rectangle_state_vk {
|
if let Some(next) = discard_rectangle_state_vk {
|
||||||
val_vk = val_vk.push_next(next);
|
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 {
|
if let Some(next) = rendering_vk {
|
||||||
val_vk = val_vk.push_next(next);
|
val_vk = val_vk.push_next(next);
|
||||||
}
|
}
|
||||||
@ -2392,10 +2472,15 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.zip(rendering_fields1_vk.as_ref())
|
.zip(rendering_fields1_vk.as_ref())
|
||||||
.map(|(subpass, fields1_vk)| subpass.to_vk_rendering(fields1_vk));
|
.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 {
|
GraphicsPipelineCreateInfoExtensionsVk {
|
||||||
discard_rectangle_state_vk,
|
discard_rectangle_state_vk,
|
||||||
rendering_vk,
|
rendering_vk,
|
||||||
|
fragment_shading_rate_vk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2608,6 +2693,8 @@ pub(crate) struct GraphicsPipelineCreateInfoExtensionsVk<'a> {
|
|||||||
pub(crate) discard_rectangle_state_vk:
|
pub(crate) discard_rectangle_state_vk:
|
||||||
Option<ash::vk::PipelineDiscardRectangleStateCreateInfoEXT<'a>>,
|
Option<ash::vk::PipelineDiscardRectangleStateCreateInfoEXT<'a>>,
|
||||||
pub(crate) rendering_vk: Option<ash::vk::PipelineRenderingCreateInfo<'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> {
|
pub(crate) struct GraphicsPipelineCreateInfoFields1Vk<'a> {
|
||||||
|
@ -588,12 +588,15 @@ vulkan_enum! {
|
|||||||
RequiresAllOf([DeviceExtension(nv_scissor_exclusive)]),
|
RequiresAllOf([DeviceExtension(nv_scissor_exclusive)]),
|
||||||
]), */
|
]), */
|
||||||
|
|
||||||
/* TODO: enable
|
/// The value of
|
||||||
// TODO: document
|
/// [`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
|
FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR
|
||||||
RequiresOneOf([
|
RequiresOneOf([
|
||||||
RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]),
|
RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]),
|
||||||
]), */
|
]),
|
||||||
|
|
||||||
/// The value of
|
/// The value of
|
||||||
/// [`RasterizationState::line_stipple`](crate::pipeline::graphics::rasterization::RasterizationState::line_stipple).
|
/// [`RasterizationState::line_stipple`](crate::pipeline::graphics::rasterization::RasterizationState::line_stipple).
|
||||||
|
Loading…
Reference in New Issue
Block a user