blob: 52781f4a6f92d4ebc4cd67043499e529f26e7446 [file] [log] [blame]
// 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"
}
}
)
}
}