use super::device::DeviceInner;
use super::{Device, Error, Result, check};
use crate::raw::bindings::*;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QueryType(pub VkQueryType);
impl QueryType {
pub const OCCLUSION: Self = Self(VkQueryType::QUERY_TYPE_OCCLUSION);
pub const PIPELINE_STATISTICS: Self = Self(VkQueryType::QUERY_TYPE_PIPELINE_STATISTICS);
pub const TIMESTAMP: Self = Self(VkQueryType::QUERY_TYPE_TIMESTAMP);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PipelineStatisticsFlags(pub u32);
impl PipelineStatisticsFlags {
pub const NONE: Self = Self(0);
pub const INPUT_ASSEMBLY_VERTICES: Self = Self(0x1);
pub const INPUT_ASSEMBLY_PRIMITIVES: Self = Self(0x2);
pub const VERTEX_SHADER_INVOCATIONS: Self = Self(0x4);
pub const GEOMETRY_SHADER_INVOCATIONS: Self = Self(0x8);
pub const GEOMETRY_SHADER_PRIMITIVES: Self = Self(0x10);
pub const CLIPPING_INVOCATIONS: Self = Self(0x20);
pub const CLIPPING_PRIMITIVES: Self = Self(0x40);
pub const FRAGMENT_SHADER_INVOCATIONS: Self = Self(0x80);
pub const TESSELLATION_CONTROL_SHADER_PATCHES: Self = Self(0x100);
pub const TESSELLATION_EVALUATION_SHADER_INVOCATIONS: Self = Self(0x200);
pub const COMPUTE_SHADER_INVOCATIONS: Self = Self(0x400);
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub const fn count(self) -> u32 {
self.0.count_ones()
}
}
impl std::ops::BitOr for PipelineStatisticsFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
pub struct QueryPool {
pub(crate) handle: VkQueryPool,
pub(crate) device: Arc<DeviceInner>,
pub(crate) query_count: u32,
pub(crate) values_per_query: u32,
}
impl QueryPool {
pub fn timestamps(device: &Device, query_count: u32) -> Result<Self> {
Self::new_inner(
device,
QueryType::TIMESTAMP,
query_count,
PipelineStatisticsFlags::NONE,
1,
)
}
pub fn pipeline_statistics(
device: &Device,
query_count: u32,
stats: PipelineStatisticsFlags,
) -> Result<Self> {
debug_assert!(
stats.0 != 0,
"pipeline_statistics requires at least one bit set"
);
Self::new_inner(
device,
QueryType::PIPELINE_STATISTICS,
query_count,
stats,
stats.count(),
)
}
fn new_inner(
device: &Device,
query_type: QueryType,
query_count: u32,
pipeline_stats: PipelineStatisticsFlags,
values_per_query: u32,
) -> Result<Self> {
let create = device
.inner
.dispatch
.vkCreateQueryPool
.ok_or(Error::MissingFunction("vkCreateQueryPool"))?;
let info = VkQueryPoolCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
queryType: query_type.0,
queryCount: query_count,
pipelineStatistics: pipeline_stats.0,
..Default::default()
};
let mut handle: VkQueryPool = 0;
check(unsafe { create(device.inner.handle, &info, std::ptr::null(), &mut handle) })?;
Ok(Self {
handle,
device: Arc::clone(&device.inner),
query_count,
values_per_query,
})
}
pub fn raw(&self) -> VkQueryPool {
self.handle
}
pub fn query_count(&self) -> u32 {
self.query_count
}
pub fn get_results_u64(&self, first_query: u32, query_count: u32) -> Result<Vec<u64>> {
let get = self
.device
.dispatch
.vkGetQueryPoolResults
.ok_or(Error::MissingFunction("vkGetQueryPoolResults"))?;
let total = (query_count as usize) * (self.values_per_query as usize);
let mut data: Vec<u64> = vec![0; total];
let stride = (self.values_per_query as u64) * 8;
let flags: u32 = 0x1 | 0x2;
check(unsafe {
get(
self.device.handle,
self.handle,
first_query,
query_count,
total * 8,
data.as_mut_ptr() as *mut _,
stride,
flags,
)
})?;
Ok(data)
}
}
impl Drop for QueryPool {
fn drop(&mut self) {
if let Some(destroy) = self.device.dispatch.vkDestroyQueryPool {
unsafe { destroy(self.device.handle, self.handle, std::ptr::null()) };
}
}
}