aboutsummaryrefslogtreecommitdiff
path: root/src/command_buffer/validity/query.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/command_buffer/validity/query.rs')
-rw-r--r--src/command_buffer/validity/query.rs391
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"
+ }
+ }
+ )
+ }
+}