| // 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" |
| } |
| } |
| ) |
| } |
| } |