Add QueryPoolCreateInfo (#1840)

This commit is contained in:
Rua 2022-02-26 00:52:59 +01:00 committed by GitHub
parent 7ee0a93d92
commit c61ed1bfe3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 61 deletions

View File

@ -25,7 +25,9 @@ use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::query::{QueryControlFlags, QueryPool, QueryResultFlags, QueryType};
use vulkano::query::{
QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType,
};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
@ -187,7 +189,14 @@ fn main() {
let triangle3 = vertex_buffer.slice(6..9).unwrap();
// Create a query pool for occlusion queries, with 3 slots.
let query_pool = QueryPool::new(device.clone(), QueryType::Occlusion, 3).unwrap();
let query_pool = QueryPool::new(
device.clone(),
QueryPoolCreateInfo {
query_count: 3,
..QueryPoolCreateInfo::query_type(QueryType::Occlusion)
},
)
.unwrap();
// Create a buffer on the CPU to hold the results of the three queries.
// Query results are always represented as either `u32` or `u64`.

View File

@ -3054,7 +3054,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
) -> Result<&mut Self, BeginQueryError> {
check_begin_query(self.device(), &query_pool, query, flags)?;
match query_pool.ty() {
match query_pool.query_type() {
QueryType::Occlusion => {
if !self.queue_family().supports_graphics() {
return Err(
@ -3074,7 +3074,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
QueryType::Timestamp => unreachable!(),
}
let ty = query_pool.ty();
let ty = query_pool.query_type();
let raw_ty = ty.into();
let raw_query_pool = query_pool.internal_object();
if self.query_state.contains_key(&raw_ty) {
@ -3106,7 +3106,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
unsafe {
check_end_query(self.device(), &query_pool, query)?;
let raw_ty = query_pool.ty().into();
let raw_ty = query_pool.query_type().into();
let raw_query_pool = query_pool.internal_object();
if !self.query_state.get(&raw_ty).map_or(false, |state| {
state.query_pool == raw_query_pool && state.query == query

View File

@ -43,7 +43,7 @@ pub fn check_begin_query(
.query(query)
.ok_or(CheckBeginQueryError::OutOfRange)?;
match query_pool.ty() {
match query_pool.query_type() {
QueryType::Occlusion => {
if flags.precise && !device.enabled_features().occlusion_query_precise {
return Err(CheckBeginQueryError::OcclusionQueryPreciseFeatureNotEnabled);
@ -162,7 +162,7 @@ pub fn check_write_timestamp(
query_pool.device().internal_object(),
);
if !matches!(query_pool.ty(), QueryType::Timestamp) {
if !matches!(query_pool.query_type(), QueryType::Timestamp) {
return Err(CheckWriteTimestampError::NotPermitted);
}

View File

@ -13,44 +13,59 @@
//! represent a collection of queries. Whenever you use a query, you have to specify both the query
//! pool and the slot id within that query pool.
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::DeviceSize;
use crate::Error;
use crate::OomError;
use crate::Success;
use crate::VulkanObject;
use std::error;
use std::ffi::c_void;
use std::fmt;
use std::mem::MaybeUninit;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use crate::{
check_errors,
device::{Device, DeviceOwned},
DeviceSize, Error, OomError, Success, VulkanObject,
};
use std::{
error,
ffi::c_void,
fmt,
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::Range,
ptr,
sync::Arc,
};
/// A collection of one or more queries of a particular type.
#[derive(Debug)]
pub struct QueryPool {
pool: ash::vk::QueryPool,
handle: ash::vk::QueryPool,
device: Arc<Device>,
num_slots: u32,
ty: QueryType,
query_type: QueryType,
query_count: u32,
}
impl QueryPool {
/// Builds a new query pool.
/// Creates a new `QueryPool`.
///
/// # Panics
///
/// - Panics if `create_info.query_count` is `0`.
pub fn new(
device: Arc<Device>,
ty: QueryType,
num_slots: u32,
create_info: QueryPoolCreateInfo,
) -> Result<Arc<QueryPool>, QueryPoolCreationError> {
let statistics = match ty {
let QueryPoolCreateInfo {
query_type,
query_count,
_ne: _,
} = create_info;
// VUID-VkQueryPoolCreateInfo-queryCount-02763
assert!(query_count != 0);
let pipeline_statistics = match query_type {
QueryType::PipelineStatistics(flags) => {
// VUID-VkQueryPoolCreateInfo-queryType-00791
if !device.enabled_features().pipeline_statistics_query {
return Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled);
}
// VUID-VkQueryPoolCreateInfo-queryType-00792
flags.into()
}
QueryType::Occlusion | QueryType::Timestamp => {
@ -58,20 +73,20 @@ impl QueryPool {
}
};
let pool = unsafe {
let infos = ash::vk::QueryPoolCreateInfo {
flags: ash::vk::QueryPoolCreateFlags::empty(),
query_type: ty.into(),
query_count: num_slots,
pipeline_statistics: statistics,
..Default::default()
};
let create_info = ash::vk::QueryPoolCreateInfo {
flags: ash::vk::QueryPoolCreateFlags::empty(),
query_type: query_type.into(),
query_count,
pipeline_statistics,
..Default::default()
};
let mut output = MaybeUninit::uninit();
let handle = unsafe {
let fns = device.fns();
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_query_pool(
device.internal_object(),
&infos,
&create_info,
ptr::null(),
output.as_mut_ptr(),
))?;
@ -79,29 +94,30 @@ impl QueryPool {
};
Ok(Arc::new(QueryPool {
pool,
handle,
device,
num_slots,
ty,
query_type,
query_count,
}))
}
/// Returns the [`QueryType`] that this query pool was created with.
/// Returns the query type of the pool.
#[inline]
pub fn ty(&self) -> QueryType {
self.ty
pub fn query_type(&self) -> QueryType {
self.query_type
}
/// Returns the number of query slots of this query pool.
#[inline]
pub fn num_slots(&self) -> u32 {
self.num_slots
pub fn query_count(&self) -> u32 {
self.query_count
}
/// Returns a reference to a single query slot, or `None` if the index is out of range.
#[inline]
pub fn query(&self, index: u32) -> Option<Query> {
if index < self.num_slots() {
if index < self.query_count {
Some(Query { pool: self, index })
} else {
None
@ -117,7 +133,7 @@ impl QueryPool {
pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange> {
assert!(!range.is_empty());
if range.end <= self.num_slots() {
if range.end <= self.query_count {
Some(QueriesRange { pool: self, range })
} else {
None
@ -125,12 +141,23 @@ impl QueryPool {
}
}
impl Drop for QueryPool {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0
.destroy_query_pool(self.device.internal_object(), self.handle, ptr::null());
}
}
}
unsafe impl VulkanObject for QueryPool {
type Object = ash::vk::QueryPool;
#[inline]
fn internal_object(&self) -> ash::vk::QueryPool {
self.pool
self.handle
}
}
@ -141,13 +168,47 @@ unsafe impl DeviceOwned for QueryPool {
}
}
impl Drop for QueryPool {
impl PartialEq for QueryPool {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0
.destroy_query_pool(self.device.internal_object(), self.pool, ptr::null());
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle && self.device() == other.device()
}
}
impl Eq for QueryPool {}
impl Hash for QueryPool {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle.hash(state);
self.device().hash(state);
}
}
/// Parameters to create a new `QueryPool`.
#[derive(Clone, Debug)]
pub struct QueryPoolCreateInfo {
/// The type of query that the pool should be for.
///
/// There is no default value.
pub query_type: QueryType,
/// The number of queries to create in the pool.
///
/// The default value is `0`, which must be overridden.
pub query_count: u32,
pub _ne: crate::NonExhaustive,
}
impl QueryPoolCreateInfo {
/// Returns a `QueryPoolCreateInfo` with the specified `query_type`.
#[inline]
pub fn query_type(query_type: QueryType) -> Self {
Self {
query_type,
query_count: 0,
_ne: crate::NonExhaustive(()),
}
}
}
@ -310,7 +371,8 @@ impl<'a> QueriesRange<'a> {
debug_assert!(buffer_start % std::mem::size_of::<T>() as DeviceSize == 0);
let count = self.range.end - self.range.start;
let per_query_len = self.pool.ty.result_size() + flags.with_availability as DeviceSize;
let per_query_len =
self.pool.query_type.result_size() + flags.with_availability as DeviceSize;
let required_len = per_query_len * count as DeviceSize;
if buffer_len < required_len {
@ -320,7 +382,7 @@ impl<'a> QueriesRange<'a> {
});
}
match self.pool.ty {
match self.pool.query_type {
QueryType::Occlusion => (),
QueryType::PipelineStatistics(_) => (),
QueryType::Timestamp => {
@ -670,6 +732,7 @@ impl From<QueryResultFlags> for ash::vk::QueryResultFlags {
#[cfg(test)]
mod tests {
use super::QueryPoolCreateInfo;
use crate::query::QueryPipelineStatisticFlags;
use crate::query::QueryPool;
use crate::query::QueryPoolCreationError;
@ -678,9 +741,14 @@ mod tests {
#[test]
fn pipeline_statistics_feature() {
let (device, _) = gfx_dev_and_queue!();
let ty = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::none());
match QueryPool::new(device, ty, 256) {
let query_type = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::none());
match QueryPool::new(
device,
QueryPoolCreateInfo {
query_count: 256,
..QueryPoolCreateInfo::query_type(query_type)
},
) {
Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => (),
_ => panic!(),
};