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;
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.query_type() {
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(())
}
#[derive(Debug, Copy, Clone)]
pub enum CheckBeginQueryError {
InvalidFlags,
NotPermitted,
OcclusionQueryPreciseFeatureNotEnabled,
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"
}
}
)
}
}
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(())
}
#[derive(Debug, Copy, Clone)]
pub enum CheckEndQueryError {
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"
}
}
)
}
}
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.query_type(), 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(())
}
#[derive(Debug, Copy, Clone)]
pub enum CheckWriteTimestampError {
GeometryShaderFeatureNotEnabled,
NoTimestampValidBits,
NotPermitted,
OutOfRange,
StageNotSupported,
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"
}
}
)
}
}
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,
)?)
}
#[derive(Debug, Copy, Clone)]
pub enum CheckCopyQueryPoolResultsError {
BufferTooSmall {
required_len: DeviceSize,
actual_len: DeviceSize,
},
DestinationMissingTransferUsage,
InvalidFlags,
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"
}
}
)
}
}
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(())
}
#[derive(Debug, Copy, Clone)]
pub enum CheckResetQueryPoolError {
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"
}
}
)
}
}