mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Add support for the ext_mesh_shader
extension (#2433)
* Add support for the `ext_mesh_shader` extension * Helper function for queries * Documentation update * Add mesh primitives generated query * Derp * Support in vulkano-shaders too * More doc fixes * Better docs, explicitly saying when the values must be `Some` or `None`. * Update vulkano/src/pipeline/graphics/mod.rs 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
b2bbe34896
commit
655ca5e6c9
@ -92,10 +92,12 @@
|
|||||||
//! of the following:
|
//! of the following:
|
||||||
//!
|
//!
|
||||||
//! - `vertex`
|
//! - `vertex`
|
||||||
//! - `fragment`
|
|
||||||
//! - `geometry`
|
|
||||||
//! - `tess_ctrl`
|
//! - `tess_ctrl`
|
||||||
//! - `tess_eval`
|
//! - `tess_eval`
|
||||||
|
//! - `geometry`
|
||||||
|
//! - `task`
|
||||||
|
//! - `mesh`
|
||||||
|
//! - `fragment`
|
||||||
//! - `compute`
|
//! - `compute`
|
||||||
//! - `raygen`
|
//! - `raygen`
|
||||||
//! - `anyhit`
|
//! - `anyhit`
|
||||||
@ -421,10 +423,12 @@ impl Parse for MacroInput {
|
|||||||
|
|
||||||
output.0 = Some(match lit.value().as_str() {
|
output.0 = Some(match lit.value().as_str() {
|
||||||
"vertex" => ShaderKind::Vertex,
|
"vertex" => ShaderKind::Vertex,
|
||||||
"fragment" => ShaderKind::Fragment,
|
|
||||||
"geometry" => ShaderKind::Geometry,
|
|
||||||
"tess_ctrl" => ShaderKind::TessControl,
|
"tess_ctrl" => ShaderKind::TessControl,
|
||||||
"tess_eval" => ShaderKind::TessEvaluation,
|
"tess_eval" => ShaderKind::TessEvaluation,
|
||||||
|
"geometry" => ShaderKind::Geometry,
|
||||||
|
"task" => ShaderKind::Task,
|
||||||
|
"mesh" => ShaderKind::Mesh,
|
||||||
|
"fragment" => ShaderKind::Fragment,
|
||||||
"compute" => ShaderKind::Compute,
|
"compute" => ShaderKind::Compute,
|
||||||
"raygen" => ShaderKind::RayGeneration,
|
"raygen" => ShaderKind::RayGeneration,
|
||||||
"anyhit" => ShaderKind::AnyHit,
|
"anyhit" => ShaderKind::AnyHit,
|
||||||
@ -434,9 +438,9 @@ impl Parse for MacroInput {
|
|||||||
"callable" => ShaderKind::Callable,
|
"callable" => ShaderKind::Callable,
|
||||||
ty => bail!(
|
ty => bail!(
|
||||||
lit,
|
lit,
|
||||||
"expected `vertex`, `fragment`, `geometry`, `tess_ctrl`, `tess_eval`, \
|
"expected `vertex`, `tess_ctrl`, `tess_eval`, `geometry`, `task`, \
|
||||||
`compute`, `raygen`, `anyhit`, `closesthit`, `miss`, `intersection` or \
|
`mesh`, `fragment` `compute`, `raygen`, `anyhit`, `closesthit`, \
|
||||||
`callable`, found `{ty}`",
|
`miss`, `intersection` or `callable`, found `{ty}`",
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -505,6 +505,22 @@ impl RawRecordingCommandBuffer {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QueryType::MeshPrimitivesGenerated => {
|
||||||
|
if !queue_family_properties
|
||||||
|
.queue_flags
|
||||||
|
.intersects(QueueFlags::GRAPHICS)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`query_pool.query_type()` is \
|
||||||
|
`QueryType::MeshPrimitivesGenerated`, but \
|
||||||
|
the queue family of the command buffer does not support \
|
||||||
|
graphics operations"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-vkCmdBeginQuery-queryType-07070"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
QueryType::Timestamp
|
QueryType::Timestamp
|
||||||
| QueryType::AccelerationStructureCompactedSize
|
| QueryType::AccelerationStructureCompactedSize
|
||||||
| QueryType::AccelerationStructureSerializationSize
|
| QueryType::AccelerationStructureSerializationSize
|
||||||
|
@ -172,6 +172,31 @@ pub struct DrawIndirectCommand {
|
|||||||
pub first_instance: u32,
|
pub first_instance: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used as buffer contents to provide input for the
|
||||||
|
/// [`RecordingCommandBuffer::draw_mesh_tasks_indirect`] command.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If the graphics pipeline **does not** include a task shader, then the
|
||||||
|
/// `group_count_x`, `group_count_y` and `group_count_z` values must not be greater than the
|
||||||
|
/// respective elements of the
|
||||||
|
/// [`max_mesh_work_group_count`](Properties::max_mesh_work_group_count) device limit,
|
||||||
|
/// and the product of these three values must not be greater than the
|
||||||
|
/// [`max_mesh_work_group_total_count`](Properties::max_mesh_work_group_total_count) device limit.
|
||||||
|
/// - If the graphics pipeline **does** include a task shader, then the
|
||||||
|
/// `group_count_x`, `group_count_y` and `group_count_z` values must not be greater than the
|
||||||
|
/// respective elements of the
|
||||||
|
/// [`max_task_work_group_count`](Properties::max_task_work_group_count) device limit,
|
||||||
|
/// and the product of these three values must not be greater than the
|
||||||
|
/// [`max_task_work_group_total_count`](Properties::max_task_work_group_total_count) device limit.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
|
||||||
|
pub struct DrawMeshTasksIndirectCommand {
|
||||||
|
pub group_count_x: u32,
|
||||||
|
pub group_count_y: u32,
|
||||||
|
pub group_count_z: u32,
|
||||||
|
}
|
||||||
|
|
||||||
/// Used as buffer contents to provide input for the
|
/// Used as buffer contents to provide input for the
|
||||||
/// [`RecordingCommandBuffer::draw_indexed_indirect`] command.
|
/// [`RecordingCommandBuffer::draw_indexed_indirect`] command.
|
||||||
///
|
///
|
||||||
|
@ -2,11 +2,27 @@
|
|||||||
//!
|
//!
|
||||||
//! Unlike a compute pipeline, which performs general-purpose work, a graphics pipeline is geared
|
//! Unlike a compute pipeline, which performs general-purpose work, a graphics pipeline is geared
|
||||||
//! specifically towards doing graphical processing. To that end, it consists of several shaders,
|
//! specifically towards doing graphical processing. To that end, it consists of several shaders,
|
||||||
//! with additional state and glue logic in between.
|
//! with additional state and glue logic in between, known as the pipeline's *state*.
|
||||||
|
//! The state often directly corresponds to one or more steps in the graphics pipeline. Each
|
||||||
|
//! state collection has a dedicated submodule.
|
||||||
|
//!
|
||||||
|
//! # Processing steps
|
||||||
//!
|
//!
|
||||||
//! A graphics pipeline performs many separate steps, that execute more or less in sequence.
|
//! A graphics pipeline performs many separate steps, that execute more or less in sequence.
|
||||||
//! Due to the parallel nature of a GPU, no strict ordering guarantees may exist.
|
//! Due to the parallel nature of a GPU, no strict ordering guarantees may exist.
|
||||||
//!
|
//!
|
||||||
|
//! Graphics pipelines come in two different forms:
|
||||||
|
//! - *Primitive shading* graphics pipelines, which contain a vertex shader, vertex input and
|
||||||
|
//! input assembly state, and optionally tessellation shaders and/or a geometry shader.
|
||||||
|
//! - *Mesh shading* graphics pipelines, which contain a mesh shader, and optionally a
|
||||||
|
//! task shader.
|
||||||
|
//!
|
||||||
|
//! These types differ in the operations that are performed in the first half of the pipeline,
|
||||||
|
//! but share a common second half. The type of a graphics pipeline is determined by whether
|
||||||
|
//! it contains a vertex or a mesh shader (it cannot contain both).
|
||||||
|
//!
|
||||||
|
//! ## Primitive shading
|
||||||
|
//!
|
||||||
//! 1. Vertex input and assembly: vertex input data is read from data buffers and then assembled
|
//! 1. Vertex input and assembly: vertex input data is read from data buffers and then assembled
|
||||||
//! into primitives (points, lines, triangles etc.).
|
//! into primitives (points, lines, triangles etc.).
|
||||||
//! 2. Vertex shader invocations: the vertex data of each primitive is fed as input to the vertex
|
//! 2. Vertex shader invocations: the vertex data of each primitive is fed as input to the vertex
|
||||||
@ -17,14 +33,31 @@
|
|||||||
//! newly created vertices.
|
//! newly created vertices.
|
||||||
//! 4. (Optional) Geometry shading: whole primitives are fed as input and processed into a new set
|
//! 4. (Optional) Geometry shading: whole primitives are fed as input and processed into a new set
|
||||||
//! of output primitives.
|
//! of output primitives.
|
||||||
//! 5. Vertex post-processing, including:
|
//!
|
||||||
|
//! ## Mesh shading
|
||||||
|
//!
|
||||||
|
//! 1. (Optional) Task shader invocations: the task shader is run once for each workgroup in the
|
||||||
|
//! draw command. The task shader then spawns one or more mesh shader invocations.
|
||||||
|
//! 2. Mesh shader invocations: the mesh shader is run, either once each time it is spawned by a
|
||||||
|
//! task shader, or if there is no task shader, once for each workgroup in the draw command.
|
||||||
|
//! The mesh shader outputs a list of primitives (triangles etc).
|
||||||
|
//!
|
||||||
|
//! Mesh shading pipelines do not receive any vertex input; their input data is supplied entirely
|
||||||
|
//! from resources bound via descriptor sets, in combination with the x, y and z coordinates of
|
||||||
|
//! the current workgroup.
|
||||||
|
//!
|
||||||
|
//! ## Rasterization, fragment processing and output
|
||||||
|
//!
|
||||||
|
//! These steps are shared by all graphics pipeline types.
|
||||||
|
//!
|
||||||
|
//! 1. Vertex post-processing, including:
|
||||||
//! - Clipping primitives to the view frustum and user-defined clipping planes.
|
//! - Clipping primitives to the view frustum and user-defined clipping planes.
|
||||||
//! - Perspective division.
|
//! - Perspective division.
|
||||||
//! - Viewport mapping.
|
//! - Viewport mapping.
|
||||||
//! 6. Rasterization: converting primitives into a two-dimensional representation. Primitives may be
|
//! 2. Rasterization: converting primitives into a two-dimensional representation. Primitives may be
|
||||||
//! discarded depending on their orientation, and are then converted into a collection of
|
//! discarded depending on their orientation, and are then converted into a collection of
|
||||||
//! fragments that are processed further.
|
//! fragments that are processed further.
|
||||||
//! 7. Fragment operations. These include invocations of the fragment shader, which generates the
|
//! 3. Fragment operations. These include invocations of the fragment shader, which generates the
|
||||||
//! values to be written to the color attachment. Various testing and discarding operations can
|
//! values to be written to the color attachment. Various testing and discarding operations can
|
||||||
//! be performed both before and after the fragment shader ("early" and "late" fragment tests),
|
//! be performed both before and after the fragment shader ("early" and "late" fragment tests),
|
||||||
//! including:
|
//! including:
|
||||||
@ -34,13 +67,11 @@
|
|||||||
//! - Depth bounds test
|
//! - Depth bounds test
|
||||||
//! - Stencil test
|
//! - Stencil test
|
||||||
//! - Depth test
|
//! - Depth test
|
||||||
//! 8. Color attachment output: the final pixel data is written to a framebuffer. Blending and
|
//! 4. Color attachment output: the final pixel data is written to a framebuffer. Blending and
|
||||||
//! logical operations can be applied to combine incoming pixel data with data already present
|
//! logical operations can be applied to combine incoming pixel data with data already present
|
||||||
//! in the framebuffer.
|
//! in the framebuffer.
|
||||||
//!
|
//!
|
||||||
//! A graphics pipeline contains many configuration options, which are grouped into collections of
|
//! # Using a graphics pipeline
|
||||||
//! "state". Often, these directly correspond to one or more steps in the graphics pipeline. Each
|
|
||||||
//! state collection has a dedicated submodule.
|
|
||||||
//!
|
//!
|
||||||
//! Once a graphics pipeline has been created, you can execute it by first *binding* it in a command
|
//! Once a graphics pipeline has been created, you can execute it by first *binding* it in a command
|
||||||
//! buffer, binding the necessary vertex buffers, binding any descriptor sets, setting push
|
//! buffer, binding the necessary vertex buffers, binding any descriptor sets, setting push
|
||||||
@ -117,10 +148,9 @@ pub struct GraphicsPipeline {
|
|||||||
id: NonZeroU64,
|
id: NonZeroU64,
|
||||||
|
|
||||||
flags: PipelineCreateFlags,
|
flags: PipelineCreateFlags,
|
||||||
// TODO: replace () with an object that describes the shaders in some way.
|
shader_stages: ShaderStages,
|
||||||
shaders: HashMap<ShaderStage, ()>,
|
|
||||||
vertex_input_state: Option<VertexInputState>,
|
vertex_input_state: Option<VertexInputState>,
|
||||||
input_assembly_state: InputAssemblyState,
|
input_assembly_state: Option<InputAssemblyState>,
|
||||||
tessellation_state: Option<TessellationState>,
|
tessellation_state: Option<TessellationState>,
|
||||||
viewport_state: Option<ViewportState>,
|
viewport_state: Option<ViewportState>,
|
||||||
rasterization_state: RasterizationState,
|
rasterization_state: RasterizationState,
|
||||||
@ -137,6 +167,7 @@ pub struct GraphicsPipeline {
|
|||||||
num_used_descriptor_sets: u32,
|
num_used_descriptor_sets: u32,
|
||||||
fixed_state: HashSet<DynamicState>,
|
fixed_state: HashSet<DynamicState>,
|
||||||
fragment_tests_stages: Option<FragmentTestsStages>,
|
fragment_tests_stages: Option<FragmentTestsStages>,
|
||||||
|
mesh_is_nv: bool,
|
||||||
// Note: this is only `Some` if `vertex_input_state` is `None`.
|
// Note: this is only `Some` if `vertex_input_state` is `None`.
|
||||||
required_vertex_inputs: Option<HashMap<u32, ShaderInterfaceLocationInfo>>,
|
required_vertex_inputs: Option<HashMap<u32, ShaderInterfaceLocationInfo>>,
|
||||||
}
|
}
|
||||||
@ -917,7 +948,8 @@ impl GraphicsPipeline {
|
|||||||
_ne: _,
|
_ne: _,
|
||||||
} = create_info;
|
} = create_info;
|
||||||
|
|
||||||
let mut shaders = HashMap::default();
|
let mut shader_stages = ShaderStages::empty();
|
||||||
|
let mut mesh_is_nv = false;
|
||||||
let mut descriptor_binding_requirements: HashMap<
|
let mut descriptor_binding_requirements: HashMap<
|
||||||
(u32, u32),
|
(u32, u32),
|
||||||
DescriptorBindingRequirements,
|
DescriptorBindingRequirements,
|
||||||
@ -932,7 +964,7 @@ impl GraphicsPipeline {
|
|||||||
|
|
||||||
let entry_point_info = entry_point.info();
|
let entry_point_info = entry_point.info();
|
||||||
let stage = ShaderStage::from(entry_point_info.execution_model);
|
let stage = ShaderStage::from(entry_point_info.execution_model);
|
||||||
shaders.insert(stage, ());
|
shader_stages |= stage.into();
|
||||||
|
|
||||||
let spirv = entry_point.module().spirv();
|
let spirv = entry_point.module().spirv();
|
||||||
let entry_point_function = spirv.function(entry_point.id());
|
let entry_point_function = spirv.function(entry_point.id());
|
||||||
@ -947,6 +979,7 @@ impl GraphicsPipeline {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ExecutionModel::MeshNV | ExecutionModel::TaskNV => mesh_is_nv = true,
|
||||||
ExecutionModel::Fragment => {
|
ExecutionModel::Fragment => {
|
||||||
fragment_tests_stages = Some(FragmentTestsStages::Late);
|
fragment_tests_stages = Some(FragmentTestsStages::Late);
|
||||||
|
|
||||||
@ -1055,9 +1088,9 @@ impl GraphicsPipeline {
|
|||||||
id: Self::next_id(),
|
id: Self::next_id(),
|
||||||
|
|
||||||
flags,
|
flags,
|
||||||
shaders,
|
shader_stages,
|
||||||
vertex_input_state,
|
vertex_input_state,
|
||||||
input_assembly_state: input_assembly_state.unwrap(), // Can be None if there's a mesh shader, but we don't support that yet
|
input_assembly_state,
|
||||||
tessellation_state,
|
tessellation_state,
|
||||||
viewport_state,
|
viewport_state,
|
||||||
rasterization_state: rasterization_state.unwrap(), // Can be None for pipeline libraries, but we don't support that yet
|
rasterization_state: rasterization_state.unwrap(), // Can be None for pipeline libraries, but we don't support that yet
|
||||||
@ -1074,6 +1107,7 @@ impl GraphicsPipeline {
|
|||||||
num_used_descriptor_sets,
|
num_used_descriptor_sets,
|
||||||
fixed_state,
|
fixed_state,
|
||||||
fragment_tests_stages,
|
fragment_tests_stages,
|
||||||
|
mesh_is_nv,
|
||||||
required_vertex_inputs,
|
required_vertex_inputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1090,16 +1124,15 @@ impl GraphicsPipeline {
|
|||||||
self.flags
|
self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns information about a particular shader.
|
/// Returns the shader stages that this pipeline contains.
|
||||||
///
|
|
||||||
/// `None` is returned if the pipeline does not contain this shader.
|
|
||||||
///
|
|
||||||
/// Compatibility note: `()` is temporary, it will be replaced with something else in the
|
|
||||||
/// future.
|
|
||||||
// TODO: ^ implement and make this public
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn shader(&self, stage: ShaderStage) -> Option<()> {
|
pub fn shader_stages(&self) -> ShaderStages {
|
||||||
self.shaders.get(&stage).copied()
|
self.shader_stages
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn mesh_is_nv(&self) -> bool {
|
||||||
|
self.mesh_is_nv
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the vertex input state used to create this pipeline.
|
/// Returns the vertex input state used to create this pipeline.
|
||||||
@ -1110,8 +1143,8 @@ impl GraphicsPipeline {
|
|||||||
|
|
||||||
/// Returns the input assembly state used to create this pipeline.
|
/// Returns the input assembly state used to create this pipeline.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn input_assembly_state(&self) -> &InputAssemblyState {
|
pub fn input_assembly_state(&self) -> Option<&InputAssemblyState> {
|
||||||
&self.input_assembly_state
|
self.input_assembly_state.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the tessellation state used to create this pipeline.
|
/// Returns the tessellation state used to create this pipeline.
|
||||||
@ -1251,35 +1284,39 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
|
|
||||||
/// The shader stages to use.
|
/// The shader stages to use.
|
||||||
///
|
///
|
||||||
/// A vertex shader must always be included. Other stages are optional.
|
/// Either a vertex shader or mesh shader must always be included. Other stages are optional.
|
||||||
///
|
///
|
||||||
/// The default value is empty.
|
/// The default value is empty.
|
||||||
pub stages: SmallVec<[PipelineShaderStageCreateInfo; 5]>,
|
pub stages: SmallVec<[PipelineShaderStageCreateInfo; 5]>,
|
||||||
|
|
||||||
/// The vertex input state.
|
/// The vertex input state.
|
||||||
///
|
///
|
||||||
/// This state is always used, and must be provided.
|
/// This must be `Some` if `stages` contains a vertex shader.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub vertex_input_state: Option<VertexInputState>,
|
pub vertex_input_state: Option<VertexInputState>,
|
||||||
|
|
||||||
/// The input assembly state.
|
/// The input assembly state.
|
||||||
///
|
///
|
||||||
/// This state is always used, and must be provided.
|
/// This must be `Some` if `stages` contains a vertex shader.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub input_assembly_state: Option<InputAssemblyState>,
|
pub input_assembly_state: Option<InputAssemblyState>,
|
||||||
|
|
||||||
/// The tessellation state.
|
/// The tessellation state.
|
||||||
///
|
///
|
||||||
/// This state is used if `stages` contains tessellation shaders.
|
/// This must be `Some` if `stages` contains tessellation shaders.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub tessellation_state: Option<TessellationState>,
|
pub tessellation_state: Option<TessellationState>,
|
||||||
|
|
||||||
/// The viewport state.
|
/// The viewport state.
|
||||||
///
|
///
|
||||||
/// This state is used if [rasterizer discarding] is not enabled.
|
/// This must be `Some` if [rasterizer discarding] is not enabled.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
///
|
///
|
||||||
@ -1288,14 +1325,15 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
|
|
||||||
/// The rasterization state.
|
/// The rasterization state.
|
||||||
///
|
///
|
||||||
/// This state is always used, and must be provided.
|
/// This must always be `Some`.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub rasterization_state: Option<RasterizationState>,
|
pub rasterization_state: Option<RasterizationState>,
|
||||||
|
|
||||||
/// The multisample state.
|
/// The multisample state.
|
||||||
///
|
///
|
||||||
/// This state is used if [rasterizer discarding] is not enabled.
|
/// This must be `Some` if [rasterizer discarding] is not enabled.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
///
|
///
|
||||||
@ -1304,8 +1342,9 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
|
|
||||||
/// The depth/stencil state.
|
/// The depth/stencil state.
|
||||||
///
|
///
|
||||||
/// This state is used if `render_pass` has depth/stencil attachments, or if
|
/// This must be `Some` if `render_pass` has depth/stencil attachments, or if
|
||||||
/// [rasterizer discarding] is enabled.
|
/// [rasterizer discarding] is enabled.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
///
|
///
|
||||||
@ -1314,8 +1353,9 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
|
|
||||||
/// The color blend state.
|
/// The color blend state.
|
||||||
///
|
///
|
||||||
/// This state is used if `render_pass` has color attachments, and [rasterizer discarding] is
|
/// This must be `Some` if `render_pass` has color attachments, and [rasterizer discarding] is
|
||||||
/// not enabled.
|
/// not enabled.
|
||||||
|
/// It must be `None` otherwise.
|
||||||
///
|
///
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
///
|
///
|
||||||
@ -1350,8 +1390,6 @@ pub struct GraphicsPipelineCreateInfo {
|
|||||||
|
|
||||||
/// The discard rectangle state.
|
/// The discard rectangle state.
|
||||||
///
|
///
|
||||||
/// This state is always used if it is provided.
|
|
||||||
///
|
|
||||||
/// The default value is `None`.
|
/// The default value is `None`.
|
||||||
pub discard_rectangle_state: Option<DiscardRectangleState>,
|
pub discard_rectangle_state: Option<DiscardRectangleState>,
|
||||||
|
|
||||||
@ -1448,17 +1486,17 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
Gather shader stages
|
Gather shader stages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut stages_present = ShaderStages::empty();
|
const PRIMITIVE_SHADING_STAGES: ShaderStages = ShaderStages::VERTEX
|
||||||
let mut vertex_stage = None;
|
.union(ShaderStages::TESSELLATION_CONTROL)
|
||||||
let mut tessellation_control_stage = None;
|
.union(ShaderStages::TESSELLATION_CONTROL)
|
||||||
let mut tessellation_evaluation_stage = None;
|
.union(ShaderStages::GEOMETRY);
|
||||||
let mut geometry_stage = None;
|
const MESH_SHADING_STAGES: ShaderStages = ShaderStages::MESH.union(ShaderStages::TASK);
|
||||||
let mut fragment_stage = None;
|
|
||||||
|
|
||||||
for (stage_index, stage) in stages.iter().enumerate() {
|
let mut stages_present = ShaderStages::empty();
|
||||||
let entry_point_info = stage.entry_point.info();
|
|
||||||
let stage_enum = ShaderStage::from(entry_point_info.execution_model);
|
for stage in stages {
|
||||||
let stage_flag = ShaderStages::from(stage_enum);
|
let stage_flag =
|
||||||
|
ShaderStages::from(ShaderStage::from(stage.entry_point.info().execution_model));
|
||||||
|
|
||||||
if stages_present.intersects(stage_flag) {
|
if stages_present.intersects(stage_flag) {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -1474,43 +1512,6 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRIMITIVE_SHADING_STAGES: ShaderStages = ShaderStages::VERTEX
|
|
||||||
.union(ShaderStages::TESSELLATION_CONTROL)
|
|
||||||
.union(ShaderStages::TESSELLATION_CONTROL)
|
|
||||||
.union(ShaderStages::GEOMETRY);
|
|
||||||
const MESH_SHADING_STAGES: ShaderStages = ShaderStages::MESH.union(ShaderStages::TASK);
|
|
||||||
|
|
||||||
if stage_flag.intersects(PRIMITIVE_SHADING_STAGES)
|
|
||||||
&& stages_present.intersects(MESH_SHADING_STAGES)
|
|
||||||
|| stage_flag.intersects(MESH_SHADING_STAGES)
|
|
||||||
&& stages_present.intersects(PRIMITIVE_SHADING_STAGES)
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "stages".into(),
|
|
||||||
problem: "contains both primitive shading stages and mesh shading stages"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-02095"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let stage_slot = match stage_enum {
|
|
||||||
ShaderStage::Vertex => &mut vertex_stage,
|
|
||||||
ShaderStage::TessellationControl => &mut tessellation_control_stage,
|
|
||||||
ShaderStage::TessellationEvaluation => &mut tessellation_evaluation_stage,
|
|
||||||
ShaderStage::Geometry => &mut geometry_stage,
|
|
||||||
ShaderStage::Fragment => &mut fragment_stage,
|
|
||||||
_ => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: format!("stages[{}]", stage_index).into(),
|
|
||||||
problem: "is not a pre-rasterization or fragment shader stage".into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06896"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
*stage_slot = Some(stage);
|
|
||||||
stages_present |= stage_flag;
|
stages_present |= stage_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,13 +1549,8 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let need_vertex_input_state = need_pre_rasterization_shader_state
|
let need_vertex_input_state =
|
||||||
&& stages.iter().any(|stage| {
|
need_pre_rasterization_shader_state && stages_present.intersects(ShaderStages::VERTEX);
|
||||||
matches!(
|
|
||||||
stage.entry_point.info().execution_model,
|
|
||||||
ExecutionModel::Vertex
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let need_fragment_shader_state = need_pre_rasterization_shader_state
|
let need_fragment_shader_state = need_pre_rasterization_shader_state
|
||||||
&& (!rasterization_state
|
&& (!rasterization_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -1568,109 +1564,34 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
.rasterizer_discard_enable
|
.rasterizer_discard_enable
|
||||||
|| dynamic_state.contains(&DynamicState::RasterizerDiscardEnable));
|
|| dynamic_state.contains(&DynamicState::RasterizerDiscardEnable));
|
||||||
|
|
||||||
match (vertex_stage.is_some(), need_pre_rasterization_shader_state) {
|
if need_pre_rasterization_shader_state {
|
||||||
(true, false) => {
|
if !stages_present.intersects(ShaderStages::VERTEX | ShaderStages::MESH) {
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the pipeline is not being created with \
|
|
||||||
pre-rasterization shader state, but `stages` contains a \
|
|
||||||
`ShaderStage::Vertex` stage"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
(false, true) => {
|
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
problem: "the pipeline is being created with \
|
problem: "the pipeline is being created with \
|
||||||
pre-rasterization shader state, but `stages` does not contain a \
|
pre-rasterization shader state, but `stages` does not contain a \
|
||||||
`ShaderStage::Vertex` stage"
|
`ShaderStage::Vertex` or `ShaderStage::Mesh` stage"
|
||||||
.into(),
|
.into(),
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-stage-02096"],
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-stage-02096"],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
_ => (),
|
} else {
|
||||||
}
|
if stages_present.intersects(PRIMITIVE_SHADING_STAGES | MESH_SHADING_STAGES) {
|
||||||
|
|
||||||
match (
|
|
||||||
tessellation_control_stage.is_some(),
|
|
||||||
need_pre_rasterization_shader_state,
|
|
||||||
) {
|
|
||||||
(true, false) => {
|
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
problem: "the pipeline is not being created with \
|
problem: "the pipeline is not being created with \
|
||||||
pre-rasterization shader state, but `stages` contains a \
|
pre-rasterization shader state, but `stages` contains a \
|
||||||
`ShaderStage::TessellationControl` stage"
|
pre-rasterization shader stage"
|
||||||
.into(),
|
.into(),
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"],
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
(false, true) => (),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match (
|
match (
|
||||||
tessellation_evaluation_stage.is_some(),
|
stages_present.intersects(ShaderStages::FRAGMENT),
|
||||||
need_pre_rasterization_shader_state,
|
need_fragment_shader_state,
|
||||||
) {
|
) {
|
||||||
(true, false) => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the pipeline is not being created with \
|
|
||||||
pre-rasterization shader state, but `stages` contains a \
|
|
||||||
`ShaderStage::TessellationEvaluation` stage"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
(false, true) => (),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
if stages_present.intersects(ShaderStages::TESSELLATION_CONTROL)
|
|
||||||
&& !stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION)
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "stages".into(),
|
|
||||||
problem: "contains a `ShaderStage::TessellationControl` stage, but not a \
|
|
||||||
`ShaderStage::TessellationEvaluation` stage"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00729"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
} else if stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION)
|
|
||||||
&& !stages_present.intersects(ShaderStages::TESSELLATION_CONTROL)
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "stages".into(),
|
|
||||||
problem: "contains a `ShaderStage::TessellationEvaluation` stage, but not a \
|
|
||||||
`ShaderStage::TessellationControl` stage"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00730"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
match (
|
|
||||||
geometry_stage.is_some(),
|
|
||||||
need_pre_rasterization_shader_state,
|
|
||||||
) {
|
|
||||||
(true, false) => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the pipeline is not being created with \
|
|
||||||
pre-rasterization shader state, but `stages` contains a \
|
|
||||||
`ShaderStage::Geometry` stage"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
(false, true) => (),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
match (fragment_stage.is_some(), need_fragment_shader_state) {
|
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
problem: "the pipeline is not being created with \
|
problem: "the pipeline is not being created with \
|
||||||
@ -1956,6 +1877,16 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
Validate shader stages individually
|
Validate shader stages individually
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
let mut has_mesh_ext = false;
|
||||||
|
let mut has_mesh_nv = false;
|
||||||
|
let mut vertex_stage = None;
|
||||||
|
let mut tessellation_control_stage = None;
|
||||||
|
let mut tessellation_evaluation_stage = None;
|
||||||
|
let mut geometry_stage = None;
|
||||||
|
let mut task_stage = None;
|
||||||
|
let mut mesh_stage = None;
|
||||||
|
let mut fragment_stage = None;
|
||||||
|
|
||||||
for (stage_index, stage) in stages.iter().enumerate() {
|
for (stage_index, stage) in stages.iter().enumerate() {
|
||||||
stage
|
stage
|
||||||
.validate(device)
|
.validate(device)
|
||||||
@ -1969,6 +1900,37 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
} = stage;
|
} = stage;
|
||||||
|
|
||||||
let entry_point_info = entry_point.info();
|
let entry_point_info = entry_point.info();
|
||||||
|
let execution_model = entry_point_info.execution_model;
|
||||||
|
|
||||||
|
match execution_model {
|
||||||
|
ExecutionModel::TaskEXT | ExecutionModel::MeshEXT => {
|
||||||
|
has_mesh_ext = true;
|
||||||
|
}
|
||||||
|
ExecutionModel::TaskNV | ExecutionModel::MeshNV => {
|
||||||
|
has_mesh_nv = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let stage_enum = ShaderStage::from(execution_model);
|
||||||
|
let stage_slot = match stage_enum {
|
||||||
|
ShaderStage::Vertex => &mut vertex_stage,
|
||||||
|
ShaderStage::TessellationControl => &mut tessellation_control_stage,
|
||||||
|
ShaderStage::TessellationEvaluation => &mut tessellation_evaluation_stage,
|
||||||
|
ShaderStage::Geometry => &mut geometry_stage,
|
||||||
|
ShaderStage::Task => &mut task_stage,
|
||||||
|
ShaderStage::Mesh => &mut mesh_stage,
|
||||||
|
ShaderStage::Fragment => &mut fragment_stage,
|
||||||
|
_ => {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: format!("stages[{}]", stage_index).into(),
|
||||||
|
problem: "is not a pre-rasterization or fragment shader stage".into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06896"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*stage_slot = Some(stage);
|
||||||
|
|
||||||
layout
|
layout
|
||||||
.ensure_compatible_with_shader(
|
.ensure_compatible_with_shader(
|
||||||
@ -1987,11 +1949,64 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ordered_stages: SmallVec<[_; 5]> = [
|
if stages_present.intersects(PRIMITIVE_SHADING_STAGES)
|
||||||
|
&& stages_present.intersects(MESH_SHADING_STAGES)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains both primitive shading stages and mesh shading stages".into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-02095"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if stages_present.intersects(ShaderStages::TESSELLATION_CONTROL)
|
||||||
|
&& !stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains a `ShaderStage::TessellationControl` stage, but not a \
|
||||||
|
`ShaderStage::TessellationEvaluation` stage"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00729"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
} else if stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION)
|
||||||
|
&& !stages_present.intersects(ShaderStages::TESSELLATION_CONTROL)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains a `ShaderStage::TessellationEvaluation` stage, but not a \
|
||||||
|
`ShaderStage::TessellationControl` stage"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00730"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_mesh_ext && has_mesh_nv {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains mesh shader stages from both the EXT and the NV version".into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-TaskNV-07063"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// VUID-VkGraphicsPipelineCreateInfo-layout-01688
|
||||||
|
// Checked at pipeline layout creation time.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check compatibility between shader interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
let ordered_stages: SmallVec<[_; 7]> = [
|
||||||
vertex_stage,
|
vertex_stage,
|
||||||
tessellation_control_stage,
|
tessellation_control_stage,
|
||||||
tessellation_evaluation_stage,
|
tessellation_evaluation_stage,
|
||||||
geometry_stage,
|
geometry_stage,
|
||||||
|
task_stage,
|
||||||
|
mesh_stage,
|
||||||
fragment_stage,
|
fragment_stage,
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -2044,9 +2059,6 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VUID-VkGraphicsPipelineCreateInfo-layout-01688
|
|
||||||
// Checked at pipeline layout creation time.
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Validate states individually
|
Validate states individually
|
||||||
*/
|
*/
|
||||||
@ -2061,9 +2073,6 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
input_assembly_state
|
input_assembly_state
|
||||||
.validate(device)
|
.validate(device)
|
||||||
.map_err(|err| err.add_context("input_assembly_state"))?;
|
.map_err(|err| err.add_context("input_assembly_state"))?;
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// VUID-VkGraphicsPipelineCreateInfo-topology-00737
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(tessellation_state) = tessellation_state {
|
if let Some(tessellation_state) = tessellation_state {
|
||||||
@ -2076,7 +2085,133 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
viewport_state
|
viewport_state
|
||||||
.validate(device)
|
.validate(device)
|
||||||
.map_err(|err| err.add_context("viewport_state"))?;
|
.map_err(|err| err.add_context("viewport_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rasterization_state) = rasterization_state {
|
||||||
|
rasterization_state
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("rasterization_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(multisample_state) = multisample_state {
|
||||||
|
multisample_state
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("multisample_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(depth_stencil_state) = depth_stencil_state {
|
||||||
|
depth_stencil_state
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("depth_stencil_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(color_blend_state) = color_blend_state {
|
||||||
|
color_blend_state
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("color_blend_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(subpass) = subpass {
|
||||||
|
match subpass {
|
||||||
|
PipelineSubpassType::BeginRenderPass(subpass) => {
|
||||||
|
// VUID-VkGraphicsPipelineCreateInfo-commonparent
|
||||||
|
assert_eq!(device, subpass.render_pass().device().as_ref());
|
||||||
|
}
|
||||||
|
PipelineSubpassType::BeginRendering(rendering_info) => {
|
||||||
|
if !device.enabled_features().dynamic_rendering {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "subpass".into(),
|
||||||
|
problem: "is `PipelineRenderPassType::BeginRendering`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"dynamic_rendering",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
rendering_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("subpass"))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(discard_rectangle_state) = discard_rectangle_state {
|
||||||
|
if !device.enabled_extensions().ext_discard_rectangles {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "discard_rectangle_state".into(),
|
||||||
|
problem: "is `Some`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
||||||
|
"ext_discard_rectangles",
|
||||||
|
)])]),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
discard_rectangle_state
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("discard_rectangle_state"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for dynamic_state in dynamic_state.iter().copied() {
|
||||||
|
dynamic_state.validate_device(device).map_err(|err| {
|
||||||
|
err.add_context("dynamic_state")
|
||||||
|
.set_vuids(&["VUID-VkPipelineDynamicStateCreateInfo-pDynamicStates-parameter"])
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check dynamic states against other things
|
||||||
|
*/
|
||||||
|
|
||||||
|
if stages_present.intersects(ShaderStages::MESH) {
|
||||||
|
if dynamic_state.contains(&DynamicState::PrimitiveTopology) {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` includes a mesh shader, but `dynamic_state` contains \
|
||||||
|
`DynamicState::PrimitiveTopology`"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07065"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if dynamic_state.contains(&DynamicState::PrimitiveRestartEnable) {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` includes a mesh shader, but `dynamic_state` contains \
|
||||||
|
`DynamicState::PrimitiveRestartEnable`"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if dynamic_state.contains(&DynamicState::PatchControlPoints) {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` includes a mesh shader, but `dynamic_state` contains \
|
||||||
|
`DynamicState::PatchControlPoints`"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if dynamic_state.contains(&DynamicState::VertexInput) {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` includes a mesh shader, but `dynamic_state` contains \
|
||||||
|
`DynamicState::VertexInput`"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07067"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_input_assembly_state) = input_assembly_state {
|
||||||
|
// TODO:
|
||||||
|
// VUID-VkGraphicsPipelineCreateInfo-topology-00737
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(viewport_state) = viewport_state {
|
||||||
let ViewportState {
|
let ViewportState {
|
||||||
ref viewports,
|
ref viewports,
|
||||||
ref scissors,
|
ref scissors,
|
||||||
@ -2152,10 +2287,6 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rasterization_state) = rasterization_state {
|
if let Some(rasterization_state) = rasterization_state {
|
||||||
rasterization_state
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("rasterization_state"))?;
|
|
||||||
|
|
||||||
let &RasterizationState {
|
let &RasterizationState {
|
||||||
depth_clamp_enable: _,
|
depth_clamp_enable: _,
|
||||||
rasterizer_discard_enable: _,
|
rasterizer_discard_enable: _,
|
||||||
@ -2232,20 +2363,12 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
// VUID-VkGraphicsPipelineCreateInfo-renderPass-06059
|
// VUID-VkGraphicsPipelineCreateInfo-renderPass-06059
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(multisample_state) = multisample_state {
|
if let Some(_multisample_state) = multisample_state {
|
||||||
multisample_state
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("multisample_state"))?;
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766
|
// VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(depth_stencil_state) = depth_stencil_state {
|
if let Some(depth_stencil_state) = depth_stencil_state {
|
||||||
depth_stencil_state
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("depth_stencil_state"))?;
|
|
||||||
|
|
||||||
let &DepthStencilState {
|
let &DepthStencilState {
|
||||||
flags: _,
|
flags: _,
|
||||||
ref depth,
|
ref depth,
|
||||||
@ -2287,137 +2410,6 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
// VUID-VkGraphicsPipelineCreateInfo-renderPass-06040
|
// VUID-VkGraphicsPipelineCreateInfo-renderPass-06040
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(color_blend_state) = color_blend_state {
|
|
||||||
color_blend_state
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("color_blend_state"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(subpass) = subpass {
|
|
||||||
match subpass {
|
|
||||||
PipelineSubpassType::BeginRenderPass(subpass) => {
|
|
||||||
// VUID-VkGraphicsPipelineCreateInfo-commonparent
|
|
||||||
assert_eq!(device, subpass.render_pass().device().as_ref());
|
|
||||||
|
|
||||||
if subpass.subpass_desc().view_mask != 0 {
|
|
||||||
if stages_present.intersects(
|
|
||||||
ShaderStages::TESSELLATION_CONTROL
|
|
||||||
| ShaderStages::TESSELLATION_EVALUATION,
|
|
||||||
) && !device.enabled_features().multiview_tessellation_shader
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`stages` contains tessellation shaders, and \
|
|
||||||
`subpass` has a non-zero `view_mask`"
|
|
||||||
.into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
|
|
||||||
Requires::Feature("multiview_tessellation_shader"),
|
|
||||||
])]),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06047"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if stages_present.intersects(ShaderStages::GEOMETRY)
|
|
||||||
&& !device.enabled_features().multiview_geometry_shader
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`stages` contains a geometry shader, and \
|
|
||||||
`subpass` has a non-zero `view_mask`"
|
|
||||||
.into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
|
|
||||||
Requires::Feature("multiview_geometry_shader"),
|
|
||||||
])]),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06048"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PipelineSubpassType::BeginRendering(rendering_info) => {
|
|
||||||
if !device.enabled_features().dynamic_rendering {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "subpass".into(),
|
|
||||||
problem: "is `PipelineRenderPassType::BeginRendering`".into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
|
||||||
"dynamic_rendering",
|
|
||||||
)])]),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576"],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
rendering_info
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("subpass"))?;
|
|
||||||
|
|
||||||
let &PipelineRenderingCreateInfo {
|
|
||||||
view_mask,
|
|
||||||
color_attachment_formats: _,
|
|
||||||
depth_attachment_format: _,
|
|
||||||
stencil_attachment_format: _,
|
|
||||||
_ne: _,
|
|
||||||
} = rendering_info;
|
|
||||||
|
|
||||||
if view_mask != 0 {
|
|
||||||
if stages_present.intersects(
|
|
||||||
ShaderStages::TESSELLATION_CONTROL
|
|
||||||
| ShaderStages::TESSELLATION_EVALUATION,
|
|
||||||
) && !device.enabled_features().multiview_tessellation_shader
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`stages` contains tessellation shaders, and \
|
|
||||||
`subpass.view_mask` is not 0"
|
|
||||||
.into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
|
|
||||||
Requires::Feature("multiview_tessellation_shader"),
|
|
||||||
])]),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06057"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if stages_present.intersects(ShaderStages::GEOMETRY)
|
|
||||||
&& !device.enabled_features().multiview_geometry_shader
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`stages` contains a geometry shader, and \
|
|
||||||
`subpass.view_mask` is not 0"
|
|
||||||
.into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
|
|
||||||
Requires::Feature("multiview_geometry_shader"),
|
|
||||||
])]),
|
|
||||||
vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06058"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(discard_rectangle_state) = discard_rectangle_state {
|
|
||||||
if !device.enabled_extensions().ext_discard_rectangles {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "discard_rectangle_state".into(),
|
|
||||||
problem: "is `Some`".into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
|
||||||
"ext_discard_rectangles",
|
|
||||||
)])]),
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
discard_rectangle_state
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("discard_rectangle_state"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for dynamic_state in dynamic_state.iter().copied() {
|
|
||||||
dynamic_state.validate_device(device).map_err(|err| {
|
|
||||||
err.add_context("dynamic_state")
|
|
||||||
.set_vuids(&["VUID-VkPipelineDynamicStateCreateInfo-pDynamicStates-parameter"])
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Checks that rely on multiple pieces of state
|
Checks that rely on multiple pieces of state
|
||||||
*/
|
*/
|
||||||
@ -2704,6 +2696,70 @@ impl GraphicsPipelineCreateInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(subpass) = subpass {
|
||||||
|
let view_mask = match subpass {
|
||||||
|
PipelineSubpassType::BeginRenderPass(subpass) => subpass.subpass_desc().view_mask,
|
||||||
|
PipelineSubpassType::BeginRendering(rendering_info) => rendering_info.view_mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
if view_mask != 0 {
|
||||||
|
if stages_present.intersects(
|
||||||
|
ShaderStages::TESSELLATION_CONTROL | ShaderStages::TESSELLATION_EVALUATION,
|
||||||
|
) && !device.enabled_features().multiview_tessellation_shader
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` contains tessellation shaders, and \
|
||||||
|
`subpass` has a non-zero `view_mask`"
|
||||||
|
.into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"multiview_tessellation_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &[
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-06047",
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-06057",
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if stages_present.intersects(ShaderStages::GEOMETRY)
|
||||||
|
&& !device.enabled_features().multiview_geometry_shader
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` contains a geometry shader, and \
|
||||||
|
`subpass` has a non-zero `view_mask`"
|
||||||
|
.into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"multiview_geometry_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &[
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-06048",
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-06058",
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if stages_present.intersects(ShaderStages::MESH)
|
||||||
|
&& !device.enabled_features().multiview_mesh_shader
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`stages` contains a mesh shader, and \
|
||||||
|
`subpass` has a non-zero `view_mask`"
|
||||||
|
.into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"multiview_mesh_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &[
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-07064",
|
||||||
|
"VUID-VkGraphicsPipelineCreateInfo-renderPass-07720",
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let (Some(color_blend_state), Some(subpass)) = (color_blend_state, subpass) {
|
if let (Some(color_blend_state), Some(subpass)) = (color_blend_state, subpass) {
|
||||||
let color_attachment_count = match subpass {
|
let color_attachment_count = match subpass {
|
||||||
PipelineSubpassType::BeginRenderPass(subpass) => {
|
PipelineSubpassType::BeginRenderPass(subpass) => {
|
||||||
|
@ -74,8 +74,8 @@ impl PipelineShaderStageCreateInfo {
|
|||||||
.set_vuids(&["VUID-VkPipelineShaderStageCreateInfo-flags-parameter"])
|
.set_vuids(&["VUID-VkPipelineShaderStageCreateInfo-flags-parameter"])
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let entry_point_info = entry_point.info();
|
let execution_model = entry_point.info().execution_model;
|
||||||
let stage_enum = ShaderStage::from(entry_point_info.execution_model);
|
let stage_enum = ShaderStage::from(execution_model);
|
||||||
|
|
||||||
stage_enum.validate_device(device).map_err(|err| {
|
stage_enum.validate_device(device).map_err(|err| {
|
||||||
err.add_context("entry_point.info().execution")
|
err.add_context("entry_point.info().execution")
|
||||||
@ -144,18 +144,6 @@ impl PipelineShaderStageCreateInfo {
|
|||||||
ShaderStage::Miss => (),
|
ShaderStage::Miss => (),
|
||||||
ShaderStage::Intersection => (),
|
ShaderStage::Intersection => (),
|
||||||
ShaderStage::Callable => (),
|
ShaderStage::Callable => (),
|
||||||
ShaderStage::Task => {
|
|
||||||
if !device.enabled_features().task_shader {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: "entry_point".into(),
|
|
||||||
problem: "specifies a `ShaderStage::Task` entry point".into(),
|
|
||||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
|
||||||
"task_shader",
|
|
||||||
)])]),
|
|
||||||
vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-02092"],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ShaderStage::Mesh => {
|
ShaderStage::Mesh => {
|
||||||
if !device.enabled_features().mesh_shader {
|
if !device.enabled_features().mesh_shader {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -168,6 +156,18 @@ impl PipelineShaderStageCreateInfo {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ShaderStage::Task => {
|
||||||
|
if !device.enabled_features().task_shader {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "entry_point".into(),
|
||||||
|
problem: "specifies a `ShaderStage::Task` entry point".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"task_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-02092"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
ShaderStage::SubpassShading => (),
|
ShaderStage::SubpassShading => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,17 @@ impl QueryPool {
|
|||||||
unsafe { Ok(Self::new_unchecked(device, create_info)?) }
|
unsafe { Ok(Self::new_unchecked(device, create_info)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_new(
|
||||||
|
device: &Device,
|
||||||
|
create_info: &QueryPoolCreateInfo,
|
||||||
|
) -> Result<(), Box<ValidationError>> {
|
||||||
|
create_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context("create_info"))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
pub unsafe fn new_unchecked(
|
pub unsafe fn new_unchecked(
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
@ -86,17 +97,6 @@ impl QueryPool {
|
|||||||
Ok(Self::from_handle(device, handle, create_info))
|
Ok(Self::from_handle(device, handle, create_info))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_new(
|
|
||||||
device: &Device,
|
|
||||||
create_info: &QueryPoolCreateInfo,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
|
||||||
create_info
|
|
||||||
.validate(device)
|
|
||||||
.map_err(|err| err.add_context("create_info"))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `QueryPool` from a raw object handle.
|
/// Creates a new `QueryPool` from a raw object handle.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -247,7 +247,8 @@ impl QueryPool {
|
|||||||
| QueryType::AccelerationStructureCompactedSize
|
| QueryType::AccelerationStructureCompactedSize
|
||||||
| QueryType::AccelerationStructureSerializationSize
|
| QueryType::AccelerationStructureSerializationSize
|
||||||
| QueryType::AccelerationStructureSerializationBottomLevelPointers
|
| QueryType::AccelerationStructureSerializationBottomLevelPointers
|
||||||
| QueryType::AccelerationStructureSize => (),
|
| QueryType::AccelerationStructureSize
|
||||||
|
| QueryType::MeshPrimitivesGenerated => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -373,6 +374,35 @@ impl QueryPoolCreateInfo {
|
|||||||
err.add_context("query_type.flags")
|
err.add_context("query_type.flags")
|
||||||
.set_vuids(&["VUID-VkQueryPoolCreateInfo-queryType-00792"])
|
.set_vuids(&["VUID-VkQueryPoolCreateInfo-queryType-00792"])
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if flags.intersects(
|
||||||
|
QueryPipelineStatisticFlags::TASK_SHADER_INVOCATIONS
|
||||||
|
| QueryPipelineStatisticFlags::MESH_SHADER_INVOCATIONS,
|
||||||
|
) && !device.enabled_features().mesh_shader_queries
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "query_type.flags".into(),
|
||||||
|
problem: "contains `TASK_SHADER_INVOCATIONS` or \
|
||||||
|
`MESH_SHADER_INVOCATIONS`"
|
||||||
|
.into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"mesh_shader_queries",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkQueryPoolCreateInfo-meshShaderQueries-07069"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QueryType::MeshPrimitivesGenerated => {
|
||||||
|
if !device.enabled_features().mesh_shader_queries {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "query_type".into(),
|
||||||
|
problem: "is `QueryType::MeshPrimitivesGenerated`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"mesh_shader_queries",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkQueryPoolCreateInfo-meshShaderQueries-07068"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QueryType::Occlusion
|
QueryType::Occlusion
|
||||||
| QueryType::Timestamp
|
| QueryType::Timestamp
|
||||||
@ -461,6 +491,14 @@ pub enum QueryType {
|
|||||||
///
|
///
|
||||||
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
|
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
|
||||||
AccelerationStructureSize = ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR.as_raw(),
|
AccelerationStructureSize = ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR.as_raw(),
|
||||||
|
|
||||||
|
/// Queries the number of primitives emitted from a mesh shader that reach the fragment shader.
|
||||||
|
///
|
||||||
|
/// Used with the [`begin_query`] and [`end_query`] commands.
|
||||||
|
///
|
||||||
|
/// [`begin_query`]: crate::command_buffer::RecordingCommandBuffer::begin_query
|
||||||
|
/// [`end_query`]: crate::command_buffer::RecordingCommandBuffer::end_query
|
||||||
|
MeshPrimitivesGenerated = ash::vk::QueryType::MESH_PRIMITIVES_GENERATED_EXT.as_raw(),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryType {
|
impl QueryType {
|
||||||
@ -485,7 +523,8 @@ impl QueryType {
|
|||||||
| Self::AccelerationStructureCompactedSize
|
| Self::AccelerationStructureCompactedSize
|
||||||
| Self::AccelerationStructureSerializationSize
|
| Self::AccelerationStructureSerializationSize
|
||||||
| Self::AccelerationStructureSerializationBottomLevelPointers
|
| Self::AccelerationStructureSerializationBottomLevelPointers
|
||||||
| Self::AccelerationStructureSize => 1,
|
| Self::AccelerationStructureSize
|
||||||
|
| Self::MeshPrimitivesGenerated => 1,
|
||||||
Self::PipelineStatistics(flags) => flags.count() as DeviceSize,
|
Self::PipelineStatistics(flags) => flags.count() as DeviceSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,6 +580,17 @@ impl QueryType {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QueryType::MeshPrimitivesGenerated => {
|
||||||
|
if !device.enabled_extensions().ext_mesh_shader {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "is `QueryType::MeshPrimitivesGenerated`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
|
||||||
|
Requires::DeviceExtension("ext_mesh_shader"),
|
||||||
|
])]),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -566,6 +616,7 @@ impl From<&QueryType> for ash::vk::QueryType {
|
|||||||
QueryType::AccelerationStructureSize => {
|
QueryType::AccelerationStructureSize => {
|
||||||
ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR
|
ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR
|
||||||
}
|
}
|
||||||
|
QueryType::MeshPrimitivesGenerated => ash::vk::QueryType::MESH_PRIMITIVES_GENERATED_EXT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,6 +647,14 @@ vulkan_bitflags! {
|
|||||||
/// Returns `true` if `self` contains any flags referring to graphics operations.
|
/// Returns `true` if `self` contains any flags referring to graphics operations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_graphics(self) -> bool {
|
pub const fn is_graphics(self) -> bool {
|
||||||
|
self.is_primitive_shading_graphics() || self.is_mesh_shading_graphics() ||
|
||||||
|
self.intersects(QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `self` contains any flags referring to primitive shading graphics
|
||||||
|
/// operations.
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_primitive_shading_graphics(self) -> bool {
|
||||||
self.intersects(
|
self.intersects(
|
||||||
(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES)
|
(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES)
|
||||||
.union(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES)
|
.union(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES)
|
||||||
@ -604,11 +663,20 @@ vulkan_bitflags! {
|
|||||||
.union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES)
|
.union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES)
|
||||||
.union(QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS)
|
.union(QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS)
|
||||||
.union(QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES)
|
.union(QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES)
|
||||||
.union(QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS)
|
|
||||||
.union(QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES)
|
.union(QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES)
|
||||||
.union(QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS),
|
.union(QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `self` contains any flags referring to mesh shading graphics
|
||||||
|
/// operations.
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_mesh_shading_graphics(self) -> bool {
|
||||||
|
self.intersects(
|
||||||
|
(QueryPipelineStatisticFlags::TASK_SHADER_INVOCATIONS)
|
||||||
|
.union(QueryPipelineStatisticFlags::MESH_SHADER_INVOCATIONS),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
= QueryPipelineStatisticFlags(u32);
|
= QueryPipelineStatisticFlags(u32);
|
||||||
|
|
||||||
@ -645,19 +713,17 @@ vulkan_bitflags! {
|
|||||||
/// Count the number of times a compute shader is invoked.
|
/// Count the number of times a compute shader is invoked.
|
||||||
COMPUTE_SHADER_INVOCATIONS = COMPUTE_SHADER_INVOCATIONS,
|
COMPUTE_SHADER_INVOCATIONS = COMPUTE_SHADER_INVOCATIONS,
|
||||||
|
|
||||||
/* TODO: enable
|
/// Count the number of times a task shader is invoked.
|
||||||
// TODO: document
|
TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_EXT
|
||||||
TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_NV
|
|
||||||
RequiresOneOf([
|
RequiresOneOf([
|
||||||
RequiresAllOf([DeviceExtension(nv_mesh_shader)]),
|
RequiresAllOf([DeviceExtension(ext_mesh_shader)]),
|
||||||
]),*/
|
]),
|
||||||
|
|
||||||
/* TODO: enable
|
/// Count the number of times a mesh shader is invoked.
|
||||||
// TODO: document
|
MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_EXT
|
||||||
MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_NV
|
|
||||||
RequiresOneOf([
|
RequiresOneOf([
|
||||||
RequiresAllOf([DeviceExtension(nv_mesh_shader)]),
|
RequiresAllOf([DeviceExtension(ext_mesh_shader)]),
|
||||||
]),*/
|
]),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for elements of buffers that can be used as a destination for query results.
|
/// A trait for elements of buffers that can be used as a destination for query results.
|
||||||
|
Loading…
Reference in New Issue
Block a user