diff options
Diffstat (limited to 'src/command_buffer/validity/query.rs')
-rw-r--r-- | src/command_buffer/validity/query.rs | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/command_buffer/validity/query.rs b/src/command_buffer/validity/query.rs new file mode 100644 index 0000000..52781f4 --- /dev/null +++ b/src/command_buffer/validity/query.rs @@ -0,0 +1,391 @@ +// Copyright (c) 2016 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use crate::buffer::TypedBufferAccess; +use crate::device::physical::QueueFamily; +use crate::device::Device; +use crate::device::DeviceOwned; +use crate::query::GetResultsError; +use crate::query::QueryControlFlags; +use crate::query::QueryPool; +use crate::query::QueryResultElement; +use crate::query::QueryResultFlags; +use crate::query::QueryType; +use crate::sync::PipelineStage; +use crate::DeviceSize; +use crate::VulkanObject; +use std::error; +use std::fmt; +use std::ops::Range; + +/// Checks whether a `begin_query` command is valid. +/// +/// # Panic +/// +/// - Panics if the query pool was not created with `device`. +pub fn check_begin_query( + device: &Device, + query_pool: &QueryPool, + query: u32, + flags: QueryControlFlags, +) -> Result<(), CheckBeginQueryError> { + assert_eq!( + device.internal_object(), + query_pool.device().internal_object(), + ); + query_pool + .query(query) + .ok_or(CheckBeginQueryError::OutOfRange)?; + + match query_pool.ty() { + QueryType::Occlusion => { + if flags.precise && !device.enabled_features().occlusion_query_precise { + return Err(CheckBeginQueryError::OcclusionQueryPreciseFeatureNotEnabled); + } + } + QueryType::PipelineStatistics(_) => { + if flags.precise { + return Err(CheckBeginQueryError::InvalidFlags); + } + } + QueryType::Timestamp => return Err(CheckBeginQueryError::NotPermitted), + } + + Ok(()) +} + +/// Error that can happen from `check_begin_query`. +#[derive(Debug, Copy, Clone)] +pub enum CheckBeginQueryError { + /// The provided flags are not allowed for this type of query. + InvalidFlags, + /// This operation is not permitted on this query type. + NotPermitted, + /// `QueryControlFlags::precise` was requested, but the `occlusion_query_precise` feature was not enabled. + OcclusionQueryPreciseFeatureNotEnabled, + /// The provided query index is not valid for this pool. + OutOfRange, +} + +impl error::Error for CheckBeginQueryError {} + +impl fmt::Display for CheckBeginQueryError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::InvalidFlags => { + "the provided flags are not allowed for this type of query" + } + Self::NotPermitted => { + "this operation is not permitted on this query type" + } + Self::OcclusionQueryPreciseFeatureNotEnabled => { + "QueryControlFlags::precise was requested, but the occlusion_query_precise feature was not enabled" + } + Self::OutOfRange => { + "the provided query index is not valid for this pool" + } + } + ) + } +} + +/// Checks whether a `end_query` command is valid. +/// +/// # Panic +/// +/// - Panics if the query pool was not created with `device`. +pub fn check_end_query( + device: &Device, + query_pool: &QueryPool, + query: u32, +) -> Result<(), CheckEndQueryError> { + assert_eq!( + device.internal_object(), + query_pool.device().internal_object(), + ); + + query_pool + .query(query) + .ok_or(CheckEndQueryError::OutOfRange)?; + + Ok(()) +} + +/// Error that can happen from `check_end_query`. +#[derive(Debug, Copy, Clone)] +pub enum CheckEndQueryError { + /// The provided query index is not valid for this pool. + OutOfRange, +} + +impl error::Error for CheckEndQueryError {} + +impl fmt::Display for CheckEndQueryError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::OutOfRange => { + "the provided query index is not valid for this pool" + } + } + ) + } +} + +/// Checks whether a `write_timestamp` command is valid. +/// +/// # Panic +/// +/// - Panics if the query pool was not created with `device`. +pub fn check_write_timestamp( + device: &Device, + queue_family: QueueFamily, + query_pool: &QueryPool, + query: u32, + stage: PipelineStage, +) -> Result<(), CheckWriteTimestampError> { + assert_eq!( + device.internal_object(), + query_pool.device().internal_object(), + ); + + if !matches!(query_pool.ty(), QueryType::Timestamp) { + return Err(CheckWriteTimestampError::NotPermitted); + } + + query_pool + .query(query) + .ok_or(CheckWriteTimestampError::OutOfRange)?; + + if queue_family.timestamp_valid_bits().is_none() { + return Err(CheckWriteTimestampError::NoTimestampValidBits); + } + + if !queue_family.supports_stage(stage) { + return Err(CheckWriteTimestampError::StageNotSupported); + } + + match stage { + PipelineStage::GeometryShader => { + if !device.enabled_features().geometry_shader { + return Err(CheckWriteTimestampError::GeometryShaderFeatureNotEnabled); + } + } + PipelineStage::TessellationControlShader | PipelineStage::TessellationEvaluationShader => { + if !device.enabled_features().tessellation_shader { + return Err(CheckWriteTimestampError::TessellationShaderFeatureNotEnabled); + } + } + _ => (), + } + + Ok(()) +} + +/// Error that can happen from `check_write_timestamp`. +#[derive(Debug, Copy, Clone)] +pub enum CheckWriteTimestampError { + /// The geometry shader stage was requested, but the `geometry_shader` feature was not enabled. + GeometryShaderFeatureNotEnabled, + /// The queue family's `timestamp_valid_bits` value is `None`. + NoTimestampValidBits, + /// This operation is not permitted on this query type. + NotPermitted, + /// The provided query index is not valid for this pool. + OutOfRange, + /// The provided stage is not supported by the queue family. + StageNotSupported, + /// A tessellation shader stage was requested, but the `tessellation_shader` feature was not enabled. + TessellationShaderFeatureNotEnabled, +} + +impl error::Error for CheckWriteTimestampError {} + +impl fmt::Display for CheckWriteTimestampError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::GeometryShaderFeatureNotEnabled => { + "the geometry shader stage was requested, but the geometry_shader feature was not enabled" + } + Self::NoTimestampValidBits => { + "the queue family's timestamp_valid_bits value is None" + } + Self::NotPermitted => { + "this operation is not permitted on this query type" + } + Self::OutOfRange => { + "the provided query index is not valid for this pool" + } + Self::StageNotSupported => { + "the provided stage is not supported by the queue family" + } + Self::TessellationShaderFeatureNotEnabled => { + "a tessellation shader stage was requested, but the tessellation_shader feature was not enabled" + } + } + ) + } +} + +/// Checks whether a `copy_query_pool_results` command is valid. +/// +/// # Panic +/// +/// - Panics if the query pool or buffer was not created with `device`. +pub fn check_copy_query_pool_results<D, T>( + device: &Device, + query_pool: &QueryPool, + queries: Range<u32>, + destination: &D, + flags: QueryResultFlags, +) -> Result<DeviceSize, CheckCopyQueryPoolResultsError> +where + D: ?Sized + TypedBufferAccess<Content = [T]>, + T: QueryResultElement, +{ + let buffer_inner = destination.inner(); + assert_eq!( + device.internal_object(), + buffer_inner.buffer.device().internal_object(), + ); + assert_eq!( + device.internal_object(), + query_pool.device().internal_object(), + ); + + if !buffer_inner.buffer.usage().transfer_destination { + return Err(CheckCopyQueryPoolResultsError::DestinationMissingTransferUsage); + } + + let queries_range = query_pool + .queries_range(queries) + .ok_or(CheckCopyQueryPoolResultsError::OutOfRange)?; + + Ok(queries_range.check_query_pool_results::<T>( + buffer_inner.offset, + destination.len(), + flags, + )?) +} + +/// Error that can happen from `check_copy_query_pool_results`. +#[derive(Debug, Copy, Clone)] +pub enum CheckCopyQueryPoolResultsError { + /// The buffer is too small for the copy operation. + BufferTooSmall { + /// Required number of elements in the buffer. + required_len: DeviceSize, + /// Actual number of elements in the buffer. + actual_len: DeviceSize, + }, + /// The destination buffer is missing the transfer destination usage. + DestinationMissingTransferUsage, + /// The provided flags are not allowed for this type of query. + InvalidFlags, + /// The provided queries range is not valid for this pool. + OutOfRange, +} + +impl From<GetResultsError> for CheckCopyQueryPoolResultsError { + #[inline] + fn from(value: GetResultsError) -> Self { + match value { + GetResultsError::BufferTooSmall { + required_len, + actual_len, + } => CheckCopyQueryPoolResultsError::BufferTooSmall { + required_len, + actual_len, + }, + GetResultsError::InvalidFlags => CheckCopyQueryPoolResultsError::InvalidFlags, + GetResultsError::DeviceLost | GetResultsError::OomError(_) => unreachable!(), + } + } +} + +impl error::Error for CheckCopyQueryPoolResultsError {} + +impl fmt::Display for CheckCopyQueryPoolResultsError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::BufferTooSmall { .. } => { + "the buffer is too small for the copy operation" + } + Self::DestinationMissingTransferUsage => { + "the destination buffer is missing the transfer destination usage" + } + Self::InvalidFlags => { + "the provided flags are not allowed for this type of query" + } + Self::OutOfRange => { + "the provided queries range is not valid for this pool" + } + } + ) + } +} + +/// Checks whether a `reset_query_pool` command is valid. +/// +/// # Panic +/// +/// - Panics if the query pool was not created with `device`. +pub fn check_reset_query_pool( + device: &Device, + query_pool: &QueryPool, + queries: Range<u32>, +) -> Result<(), CheckResetQueryPoolError> { + assert_eq!( + device.internal_object(), + query_pool.device().internal_object(), + ); + query_pool + .queries_range(queries) + .ok_or(CheckResetQueryPoolError::OutOfRange)?; + Ok(()) +} + +/// Error that can happen from `check_reset_query_pool`. +#[derive(Debug, Copy, Clone)] +pub enum CheckResetQueryPoolError { + /// The provided queries range is not valid for this pool. + OutOfRange, +} + +impl error::Error for CheckResetQueryPoolError {} + +impl fmt::Display for CheckResetQueryPoolError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::OutOfRange => { + "the provided queries range is not valid for this pool" + } + } + ) + } +} |