Make QueryType a regular Vulkan enum (#2438)

* Make `QueryType` a regular Vulkan enum

* More consistency with Vulkan
This commit is contained in:
Rua 2024-01-02 14:08:02 +01:00 committed by GitHub
parent d08d9f587d
commit 9e82527698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 188 additions and 291 deletions

View File

@ -27,7 +27,7 @@ use crate::{
},
ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
},
query::{QueryControlFlags, QueryPool},
query::{QueryControlFlags, QueryPool, QueryType},
range_map::RangeMap,
range_set::RangeSet,
render_pass::{Framebuffer, Subpass},
@ -108,7 +108,7 @@ impl RecordingCommandBuffer {
let &CommandBufferInheritanceInfo {
ref render_pass,
occlusion_query: _,
query_statistics_flags: _,
pipeline_statistics: _,
_ne: _,
} = inheritance_info;
@ -1209,7 +1209,7 @@ pub(in crate::command_buffer) struct CommandBufferBuilderState {
pub(in crate::command_buffer) viewport_with_count: Option<SmallVec<[Viewport; 2]>>,
// Active queries
pub(in crate::command_buffer) queries: HashMap<ash::vk::QueryType, QueryState>,
pub(in crate::command_buffer) queries: HashMap<QueryType, QueryState>,
}
impl CommandBufferBuilderState {

View File

@ -2308,7 +2308,7 @@ impl RecordingCommandBuffer {
if self
.builder_state
.queries
.contains_key(&ash::vk::QueryType::MESH_PRIMITIVES_GENERATED_EXT)
.contains_key(&QueryType::MeshPrimitivesGenerated)
{
return Err(Box::new(ValidationError {
problem: "a `MeshPrimitivesGenerated` query is currently active".into(),
@ -2320,17 +2320,15 @@ impl RecordingCommandBuffer {
if let Some(query_state) = self
.builder_state
.queries
.get(&ash::vk::QueryType::PIPELINE_STATISTICS)
.get(&QueryType::PipelineStatistics)
{
let &QueryType::PipelineStatistics(pipeline_statistics_flags) =
query_state.query_pool.query_type()
else {
unreachable!()
};
if pipeline_statistics_flags.is_mesh_shading_graphics() {
if query_state
.query_pool
.pipeline_statistics()
.is_mesh_shading_graphics()
{
return Err(Box::new(ValidationError {
problem: "a pipeline statistics query is currently active, and its \
problem: "a `PipelineStatistics` query is currently active, and its \
pipeline statistics flags include statistics for mesh shading"
.into(),
vuids: vuids!(vuid_type, "stage-07073"),
@ -2385,17 +2383,15 @@ impl RecordingCommandBuffer {
if let Some(query_state) = self
.builder_state
.queries
.get(&ash::vk::QueryType::PIPELINE_STATISTICS)
.get(&QueryType::PipelineStatistics)
{
let &QueryType::PipelineStatistics(pipeline_statistics_flags) =
query_state.query_pool.query_type()
else {
unreachable!()
};
if pipeline_statistics_flags.is_primitive_shading_graphics() {
if query_state
.query_pool
.pipeline_statistics()
.is_primitive_shading_graphics()
{
return Err(Box::new(ValidationError {
problem: "a pipeline statistics query is currently active, and its \
problem: "a `PipelineStatistics` query is currently active, and its \
pipeline statistics flags include statistics for primitive shading"
.into(),
vuids: vuids!(vuid_type, "pipelineStatistics-07076"),

View File

@ -44,7 +44,7 @@ impl RecordingCommandBuffer {
if self
.builder_state
.queries
.contains_key(&query_pool.query_type().into())
.contains_key(&query_pool.query_type())
{
return Err(Box::new(ValidationError {
problem: "a query with the same type as `query_pool.query_type()` is \
@ -85,7 +85,7 @@ impl RecordingCommandBuffer {
flags: QueryControlFlags,
) -> &mut Self {
self.builder_state.queries.insert(
query_pool.query_type().into(),
query_pool.query_type(),
QueryState {
query_pool: query_pool.clone(),
query,
@ -126,7 +126,7 @@ impl RecordingCommandBuffer {
if !self
.builder_state
.queries
.get(&query_pool.query_type().into())
.get(&query_pool.query_type())
.map_or(false, |state| {
*state.query_pool == *query_pool && state.query == query
})
@ -163,8 +163,7 @@ impl RecordingCommandBuffer {
query_pool: Arc<QueryPool>,
query: u32,
) -> &mut Self {
let raw_ty = query_pool.query_type().into();
self.builder_state.queries.remove(&raw_ty);
self.builder_state.queries.remove(&query_pool.query_type());
self.add_command(
"end_query",
@ -470,16 +469,15 @@ impl RawRecordingCommandBuffer {
}));
}
}
QueryType::PipelineStatistics(statistic_flags) => {
if statistic_flags.is_graphics()
QueryType::PipelineStatistics => {
if query_pool.pipeline_statistics().is_graphics()
&& !queue_family_properties
.queue_flags
.intersects(QueueFlags::GRAPHICS)
{
return Err(Box::new(ValidationError {
context: "query_pool.query_type()".into(),
problem: "is `QueryType::PipelineStatistics`, and the \
pipeline statistics flags include a graphics flag, but \
problem: "`query_pool.query_type()` is `QueryType::PipelineStatistics`, \
and `query_pool.pipeline_statistics()` includes a graphics flag, but \
the queue family of the command buffer does not support \
graphics operations"
.into(),
@ -488,15 +486,14 @@ impl RawRecordingCommandBuffer {
}));
}
if statistic_flags.is_compute()
if query_pool.pipeline_statistics().is_compute()
&& !queue_family_properties
.queue_flags
.intersects(QueueFlags::COMPUTE)
{
return Err(Box::new(ValidationError {
context: "query_pool.query_type()".into(),
problem: "is `QueryType::PipelineStatistics`, and the \
pipeline statistics flags include a compute flag, but \
problem: "`query_pool.query_type()` is `QueryType::PipelineStatistics`, \
and `query_pool.pipeline_statistics()` includes a compute flag, but \
the queue family of the command buffer does not support \
compute operations"
.into(),
@ -965,8 +962,7 @@ impl RawRecordingCommandBuffer {
}
let count = queries.end - queries.start;
let per_query_len = query_pool.query_type().result_len()
+ flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
let per_query_len = query_pool.result_len(flags);
let required_len = per_query_len * count as DeviceSize;
if destination.len() < required_len {
@ -1017,8 +1013,7 @@ impl RawRecordingCommandBuffer {
where
T: QueryResultElement,
{
let per_query_len = query_pool.query_type().result_len()
+ flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
let per_query_len = query_pool.result_len(flags);
let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize;
let fns = self.device().fns();

View File

@ -422,18 +422,18 @@ impl RecordingCommandBuffer {
}));
}
}
&QueryType::PipelineStatistics(state_flags) => {
let inherited_flags = inheritance_info.query_statistics_flags;
QueryType::PipelineStatistics => {
let inherited_flags = inheritance_info.pipeline_statistics;
if !inherited_flags.contains(state_flags) {
if !inherited_flags.contains(state.query_pool.pipeline_statistics()) {
return Err(Box::new(ValidationError {
context: format!(
"command_buffers[{}].inheritance_info().query_statistics_flags",
"command_buffers[{}].inheritance_info().pipeline_statistics",
command_buffer_index
)
.into(),
problem: "is not a superset of the flags of the active \
pipeline statistics query"
`PipelineStatistics` query"
.into(),
vuids: &["VUID-vkCmdExecuteCommands-commandBuffer-00104"],
..Default::default()

View File

@ -285,7 +285,7 @@ pub struct CommandBufferInheritanceInfo {
/// The default value is `None`.
pub occlusion_query: Option<QueryControlFlags>,
/// Which pipeline statistics queries are allowed to be active on the primary command buffer
/// Which `PipelineStatistics` queries are allowed to be active on the primary command buffer
/// when this secondary command buffer is executed.
///
/// If this value is not empty, the [`pipeline_statistics_query`] feature must be enabled on
@ -294,7 +294,7 @@ pub struct CommandBufferInheritanceInfo {
/// The default value is [`QueryPipelineStatisticFlags::empty()`].
///
/// [`pipeline_statistics_query`]: crate::device::Features::pipeline_statistics_query
pub query_statistics_flags: QueryPipelineStatisticFlags,
pub pipeline_statistics: QueryPipelineStatisticFlags,
pub _ne: crate::NonExhaustive,
}
@ -305,7 +305,7 @@ impl Default for CommandBufferInheritanceInfo {
Self {
render_pass: None,
occlusion_query: None,
query_statistics_flags: QueryPipelineStatisticFlags::empty(),
pipeline_statistics: QueryPipelineStatisticFlags::empty(),
_ne: crate::NonExhaustive(()),
}
}
@ -316,7 +316,7 @@ impl CommandBufferInheritanceInfo {
let &Self {
ref render_pass,
occlusion_query,
query_statistics_flags,
pipeline_statistics,
_ne: _,
} = self;
@ -370,18 +370,14 @@ impl CommandBufferInheritanceInfo {
}
}
query_statistics_flags
.validate_device(device)
.map_err(|err| {
err.add_context("query_statistics_flags")
.set_vuids(&["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789"])
})?;
pipeline_statistics.validate_device(device).map_err(|err| {
err.add_context("pipeline_statistics")
.set_vuids(&["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789"])
})?;
if query_statistics_flags.count() > 0
&& !device.enabled_features().pipeline_statistics_query
{
if pipeline_statistics.count() > 0 && !device.enabled_features().pipeline_statistics_query {
return Err(Box::new(ValidationError {
context: "query_statistics_flags".into(),
context: "pipeline_statistics".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"pipeline_statistics_query",

View File

@ -98,7 +98,7 @@ impl RawRecordingCommandBuffer {
let &CommandBufferInheritanceInfo {
ref render_pass,
occlusion_query,
query_statistics_flags,
pipeline_statistics,
_ne: _,
} = inheritance_info;
@ -109,7 +109,7 @@ impl RawRecordingCommandBuffer {
framebuffer: ash::vk::Framebuffer::null(),
occlusion_query_enable: ash::vk::FALSE,
query_flags: ash::vk::QueryControlFlags::empty(),
pipeline_statistics: query_statistics_flags.into(),
pipeline_statistics: pipeline_statistics.into(),
..Default::default()
});

View File

@ -8,7 +8,7 @@ use crate::{
buffer::BufferContents,
device::{Device, DeviceOwned},
instance::InstanceOwnedDebugWrapper,
macros::{impl_id_counter, vulkan_bitflags},
macros::{impl_id_counter, vulkan_bitflags, vulkan_enum},
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError,
VulkanObject,
};
@ -30,6 +30,7 @@ pub struct QueryPool {
query_type: QueryType,
query_count: u32,
pipeline_statistics: QueryPipelineStatisticFlags,
}
impl QueryPool {
@ -61,22 +62,17 @@ impl QueryPool {
create_info: QueryPoolCreateInfo,
) -> Result<Arc<QueryPool>, VulkanError> {
let &QueryPoolCreateInfo {
ref query_type,
query_type,
query_count,
pipeline_statistics,
_ne: _,
} = &create_info;
let pipeline_statistics = if let &QueryType::PipelineStatistics(flags) = query_type {
flags.into()
} else {
ash::vk::QueryPipelineStatisticFlags::empty()
};
let create_info_vk = ash::vk::QueryPoolCreateInfo {
flags: ash::vk::QueryPoolCreateFlags::empty(),
query_type: query_type.into(),
query_count,
pipeline_statistics,
pipeline_statistics: pipeline_statistics.into(),
..Default::default()
};
@ -112,6 +108,7 @@ impl QueryPool {
let QueryPoolCreateInfo {
query_type,
query_count,
pipeline_statistics,
_ne: _,
} = create_info;
@ -121,13 +118,14 @@ impl QueryPool {
id: Self::next_id(),
query_type,
query_count,
pipeline_statistics,
})
}
/// Returns the query type of the pool.
#[inline]
pub fn query_type(&self) -> &QueryType {
&self.query_type
pub fn query_type(&self) -> QueryType {
self.query_type
}
/// Returns the number of query slots of this query pool.
@ -136,6 +134,28 @@ impl QueryPool {
self.query_count
}
/// Returns the pipeline statistics flags of this query pool.
#[inline]
pub fn pipeline_statistics(&self) -> QueryPipelineStatisticFlags {
self.pipeline_statistics
}
/// Returns the number of [`QueryResultElement`]s that are needed to hold the result of a
/// single query of this type.
#[inline]
pub const fn result_len(&self, result_flags: QueryResultFlags) -> DeviceSize {
(match self.query_type {
QueryType::Occlusion
| QueryType::Timestamp
| QueryType::AccelerationStructureCompactedSize
| QueryType::AccelerationStructureSerializationSize
| QueryType::AccelerationStructureSerializationBottomLevelPointers
| QueryType::AccelerationStructureSize
| QueryType::MeshPrimitivesGenerated => 1,
QueryType::PipelineStatistics => self.pipeline_statistics.count() as DeviceSize,
}) + result_flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize
}
/// Copies the results of a range of queries to a buffer on the CPU.
///
/// [`self.ty().result_len()`] will be written for each query in the range, plus 1 extra
@ -215,8 +235,7 @@ impl QueryPool {
// VUID-vkGetQueryPoolResults-stride-08993
// Ensured by choosing the stride ourselves.
let per_query_len = self.query_type.result_len()
+ flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
let per_query_len = self.result_len(flags);
let required_len = per_query_len * range.len() as DeviceSize;
if (destination.len() as DeviceSize) < required_len {
@ -230,25 +249,16 @@ impl QueryPool {
}));
}
match &self.query_type {
QueryType::Timestamp => {
if flags.intersects(QueryResultFlags::PARTIAL) {
return Err(Box::new(ValidationError {
problem: "`self.query_type()` is `QueryType::Timestamp`, but \
`flags` contains `QueryResultFlags::PARTIAL`"
.into(),
vuids: &["VUID-vkGetQueryPoolResults-queryType-00818"],
..Default::default()
}));
}
if self.query_type == QueryType::Timestamp {
if flags.intersects(QueryResultFlags::PARTIAL) {
return Err(Box::new(ValidationError {
problem: "`self.query_type()` is `QueryType::Timestamp`, but \
`flags` contains `QueryResultFlags::PARTIAL`"
.into(),
vuids: &["VUID-vkGetQueryPoolResults-queryType-00818"],
..Default::default()
}));
}
QueryType::Occlusion
| QueryType::PipelineStatistics(_)
| QueryType::AccelerationStructureCompactedSize
| QueryType::AccelerationStructureSerializationSize
| QueryType::AccelerationStructureSerializationBottomLevelPointers
| QueryType::AccelerationStructureSize
| QueryType::MeshPrimitivesGenerated => (),
}
Ok(())
@ -264,8 +274,7 @@ impl QueryPool {
where
T: QueryResultElement,
{
let per_query_len = self.query_type.result_len()
+ flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
let per_query_len = self.result_len(flags);
let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize;
let result = unsafe {
@ -331,6 +340,13 @@ pub struct QueryPoolCreateInfo {
/// The default value is `0`, which must be overridden.
pub query_count: u32,
/// If `query_type` is [`QueryType::PipelineStatistics`], the statistics to query.
///
/// For any other value of `query_type`, this must be empty.
///
/// The default value is empty.
pub pipeline_statistics: QueryPipelineStatisticFlags,
pub _ne: crate::NonExhaustive,
}
@ -341,14 +357,16 @@ impl QueryPoolCreateInfo {
Self {
query_type,
query_count: 0,
pipeline_statistics: QueryPipelineStatisticFlags::empty(),
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref query_type,
query_type,
query_count,
pipeline_statistics,
_ne: _,
} = self;
@ -357,61 +375,6 @@ impl QueryPoolCreateInfo {
.set_vuids(&["VUID-VkQueryPoolCreateInfo-queryType-parameter"])
})?;
match query_type {
QueryType::PipelineStatistics(flags) => {
if !device.enabled_features().pipeline_statistics_query {
return Err(Box::new(ValidationError {
context: "query_type".into(),
problem: "is `QueryType::PipelineStatistics`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"pipeline_statistics_query",
)])]),
vuids: &["VUID-VkQueryPoolCreateInfo-queryType-00791"],
}));
}
flags.validate_device(device).map_err(|err| {
err.add_context("query_type.flags")
.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::Timestamp
| QueryType::AccelerationStructureCompactedSize
| QueryType::AccelerationStructureSerializationSize
| QueryType::AccelerationStructureSerializationBottomLevelPointers
| QueryType::AccelerationStructureSize => (),
};
if query_count == 0 {
return Err(Box::new(ValidationError {
context: "query_count".into(),
@ -421,22 +384,78 @@ impl QueryPoolCreateInfo {
}));
}
if query_type == QueryType::PipelineStatistics {
if !device.enabled_features().pipeline_statistics_query {
return Err(Box::new(ValidationError {
context: "query_type".into(),
problem: "is `QueryType::PipelineStatistics`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"pipeline_statistics_query",
)])]),
vuids: &["VUID-VkQueryPoolCreateInfo-queryType-00791"],
}));
}
pipeline_statistics.validate_device(device).map_err(|err| {
err.add_context("pipeline_statistics")
.set_vuids(&["VUID-VkQueryPoolCreateInfo-queryType-00792"])
})?;
if pipeline_statistics.intersects(
QueryPipelineStatisticFlags::TASK_SHADER_INVOCATIONS
| QueryPipelineStatisticFlags::MESH_SHADER_INVOCATIONS,
) && !device.enabled_features().mesh_shader_queries
{
return Err(Box::new(ValidationError {
context: "pipeline_statistics".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"],
}));
}
} else if !pipeline_statistics.is_empty() {
return Err(Box::new(ValidationError {
problem: "`query_type` is not `QueryType::PipelineStatistics`, but \
`pipeline_statistics` is not empty"
.into(),
..Default::default()
}));
}
if query_type == QueryType::MeshPrimitivesGenerated
&& !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"],
}));
}
Ok(())
}
}
/// The type of query that a query pool should perform.
#[derive(Clone, Debug)]
#[repr(i32)]
#[non_exhaustive]
pub enum QueryType {
vulkan_enum! {
#[non_exhaustive]
/// The type of query that a query pool should perform.
QueryType = QueryType(i32);
/// Tracks the number of samples that pass per-fragment tests (e.g. the depth test).
///
/// 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
Occlusion = ash::vk::QueryType::OCCLUSION.as_raw(),
Occlusion = OCCLUSION,
/// Tracks statistics on pipeline invocations and their input data.
///
@ -444,15 +463,14 @@ pub enum QueryType {
///
/// [`begin_query`]: crate::command_buffer::RecordingCommandBuffer::begin_query
/// [`end_query`]: crate::command_buffer::RecordingCommandBuffer::end_query
PipelineStatistics(QueryPipelineStatisticFlags) =
ash::vk::QueryType::PIPELINE_STATISTICS.as_raw(),
PipelineStatistics = PIPELINE_STATISTICS,
/// Writes timestamps at chosen points in a command buffer.
///
/// Used with the [`write_timestamp`] command.
///
/// [`write_timestamp`]: crate::command_buffer::RecordingCommandBuffer::write_timestamp
Timestamp = ash::vk::QueryType::TIMESTAMP.as_raw(),
Timestamp = TIMESTAMP,
/// Queries the size of data resulting from a
/// [`CopyAccelerationStructureMode::Compact`] operation.
@ -461,8 +479,10 @@ pub enum QueryType {
///
/// [`CopyAccelerationStructureMode::Compact`]: crate::acceleration_structure::CopyAccelerationStructureMode::Compact
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
AccelerationStructureCompactedSize =
ash::vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR.as_raw(),
AccelerationStructureCompactedSize = ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_acceleration_structure)]),
]),
/// Queries the size of data resulting from a
/// [`CopyAccelerationStructureMode::Serialize`] operation.
@ -471,8 +491,10 @@ pub enum QueryType {
///
/// [`CopyAccelerationStructureMode::Serialize`]: crate::acceleration_structure::CopyAccelerationStructureMode::Serialize
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
AccelerationStructureSerializationSize =
ash::vk::QueryType::ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR.as_raw(),
AccelerationStructureSerializationSize = ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_acceleration_structure)]),
]),
/// For a top-level acceleration structure, queries the number of bottom-level acceleration
/// structure handles that will be written during a
@ -482,143 +504,32 @@ pub enum QueryType {
///
/// [`CopyAccelerationStructureMode::Serialize`]: crate::acceleration_structure::CopyAccelerationStructureMode::Serialize
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
AccelerationStructureSerializationBottomLevelPointers =
ash::vk::QueryType::ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR.as_raw(),
AccelerationStructureSerializationBottomLevelPointers = ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_ray_tracing_maintenance1)]),
]),
/// Queries the total size of an acceleration structure.
///
/// Used with the [`write_acceleration_structures_properties`] command.
///
/// [`write_acceleration_structures_properties`]: crate::command_buffer::RecordingCommandBuffer::write_acceleration_structures_properties
AccelerationStructureSize = ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR.as_raw(),
AccelerationStructureSize = ACCELERATION_STRUCTURE_SIZE_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_ray_tracing_maintenance1)]),
]),
/// 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 {
/// Returns the number of [`QueryResultElement`]s that are needed to hold the result of a
/// single query of this type.
///
/// - For [`Occlusion`] and [`Timestamp`] queries, this returns 1.
/// - For [`PipelineStatistics`] queries, this returns the number of statistics flags enabled.
///
/// If the results are retrieved with [`WITH_AVAILABILITY`] enabled, then an additional element
/// is required per query.
///
/// [`Occlusion`]: QueryType::Occlusion
/// [`Timestamp`]: QueryType::Timestamp
/// [`PipelineStatistics`]: QueryType::PipelineStatistics
/// [`WITH_AVAILABILITY`]: QueryResultFlags::WITH_AVAILABILITY
#[inline]
pub const fn result_len(&self) -> DeviceSize {
match self {
Self::Occlusion
| Self::Timestamp
| Self::AccelerationStructureCompactedSize
| Self::AccelerationStructureSerializationSize
| Self::AccelerationStructureSerializationBottomLevelPointers
| Self::AccelerationStructureSize
| Self::MeshPrimitivesGenerated => 1,
Self::PipelineStatistics(flags) => flags.count() as DeviceSize,
}
}
pub(crate) fn validate_device(&self, device: &Device) -> Result<(), Box<ValidationError>> {
match self {
QueryType::Occlusion => (),
QueryType::PipelineStatistics(_) => (),
QueryType::Timestamp => (),
QueryType::AccelerationStructureCompactedSize => {
if !device.enabled_extensions().khr_acceleration_structure {
return Err(Box::new(ValidationError {
problem: "is `QueryType::AccelerationStructureCompactedSize`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_acceleration_structure"),
])]),
..Default::default()
}));
}
}
QueryType::AccelerationStructureSerializationSize => {
if !device.enabled_extensions().khr_acceleration_structure {
return Err(Box::new(ValidationError {
problem: "is `QueryType::AccelerationStructureSerializationSize`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_acceleration_structure"),
])]),
..Default::default()
}));
}
}
QueryType::AccelerationStructureSerializationBottomLevelPointers => {
if !device.enabled_extensions().khr_ray_tracing_maintenance1 {
return Err(Box::new(ValidationError {
problem:
"is `QueryType::AccelerationStructureSerializationBottomLevelPointers`"
.into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_ray_tracing_maintenance1"),
])]),
..Default::default()
}));
}
}
QueryType::AccelerationStructureSize => {
if !device.enabled_extensions().khr_ray_tracing_maintenance1 {
return Err(Box::new(ValidationError {
problem: "is `QueryType::AccelerationStructureSize`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_ray_tracing_maintenance1"),
])]),
..Default::default()
}));
}
}
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(())
}
}
impl From<&QueryType> for ash::vk::QueryType {
#[inline]
fn from(value: &QueryType) -> Self {
match value {
QueryType::Occlusion => ash::vk::QueryType::OCCLUSION,
QueryType::PipelineStatistics(_) => ash::vk::QueryType::PIPELINE_STATISTICS,
QueryType::Timestamp => ash::vk::QueryType::TIMESTAMP,
QueryType::AccelerationStructureCompactedSize => {
ash::vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR
}
QueryType::AccelerationStructureSerializationSize => {
ash::vk::QueryType::ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR
}
QueryType::AccelerationStructureSerializationBottomLevelPointers => {
ash::vk::QueryType::ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR
}
QueryType::AccelerationStructureSize => {
ash::vk::QueryType::ACCELERATION_STRUCTURE_SIZE_KHR
}
QueryType::MeshPrimitivesGenerated => ash::vk::QueryType::MESH_PRIMITIVES_GENERATED_EXT,
}
}
MeshPrimitivesGenerated = MESH_PRIMITIVES_GENERATED_EXT
RequiresOneOf([
RequiresAllOf([DeviceExtension(ext_mesh_shader)]),
]),
}
vulkan_bitflags! {
@ -636,7 +547,7 @@ vulkan_bitflags! {
vulkan_bitflags! {
#[non_exhaustive]
/// For pipeline statistics queries, the statistics that should be gathered.
/// For `PipelineStatistics` queries, the statistics that should be gathered.
QueryPipelineStatisticFlags impl {
/// Returns `true` if `self` contains any flags referring to compute operations.
#[inline]
@ -777,20 +688,19 @@ vulkan_bitflags! {
mod tests {
use super::QueryPoolCreateInfo;
use crate::{
query::{QueryPipelineStatisticFlags, QueryPool, QueryType},
query::{QueryPool, QueryType},
Validated,
};
#[test]
fn pipeline_statistics_feature() {
let (device, _) = gfx_dev_and_queue!();
let query_type = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::empty());
assert!(matches!(
QueryPool::new(
device,
QueryPoolCreateInfo {
query_count: 256,
..QueryPoolCreateInfo::query_type(query_type)
..QueryPoolCreateInfo::query_type(QueryType::PipelineStatistics)
},
),
Err(Validated::ValidationError(_)),