1use crate::*;
2use derives::{bitflags_newtype, implements};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum QueryType {
7 Occlusion,
9 PipelineStatistics(QueryPipelineStatisticFlags),
11 Timestamp,
13}
14
15#[repr(transparent)]
17#[derive(Clone)]
18pub struct QueryPoolCreateInfo(VkQueryPoolCreateInfo);
19impl QueryPoolCreateInfo {
20 pub const fn new(query_type: QueryType, count: u32) -> Self {
21 let (qt, ps) = match query_type {
22 QueryType::Occlusion => (VK_QUERY_TYPE_OCCLUSION, 0),
23 QueryType::PipelineStatistics(st) => (VK_QUERY_TYPE_PIPELINE_STATISTICS, st.bits()),
24 QueryType::Timestamp => (VK_QUERY_TYPE_TIMESTAMP, 0),
25 };
26
27 Self(VkQueryPoolCreateInfo {
28 sType: VkQueryPoolCreateInfo::TYPE,
29 pNext: core::ptr::null(),
30 flags: 0,
31 queryType: qt,
32 queryCount: count,
33 pipelineStatistics: ps,
34 })
35 }
36
37 pub const unsafe fn from_raw(raw: VkQueryPoolCreateInfo) -> Self {
38 Self(raw)
39 }
40
41 pub const fn into_raw(self) -> VkQueryPoolCreateInfo {
42 self.0
43 }
44}
45
46#[derive(VkHandle, VkObject)]
48#[VkObject(type = VkQueryPool::OBJECT_TYPE)]
49pub struct QueryPoolObject<Device: VkHandle<Handle = VkDevice>>(VkQueryPool, Device);
50#[implements]
51impl<Device: VkHandle<Handle = VkDevice>> Drop for QueryPoolObject<Device> {
52 #[inline(always)]
53 fn drop(&mut self) {
54 unsafe {
55 crate::vkfn::destroy_query_pool(self.1.native_ptr(), self.0, core::ptr::null());
56 }
57 }
58}
59unsafe impl<Device: VkHandle<Handle = VkDevice> + Sync> Sync for QueryPoolObject<Device> {}
60unsafe impl<Device: VkHandle<Handle = VkDevice> + Send> Send for QueryPoolObject<Device> {}
61impl<Device: VkHandle<Handle = VkDevice>> DeviceChildHandle for QueryPoolObject<Device> {
62 #[inline(always)]
63 fn device_handle(&self) -> VkDevice {
64 self.1.native_ptr()
65 }
66}
67impl<Device: crate::Device> DeviceChild for QueryPoolObject<Device> {
68 type ConcreteDevice = Device;
69
70 #[inline(always)]
71 fn device(&self) -> &Self::ConcreteDevice {
72 &self.1
73 }
74}
75impl<Device: VkHandle<Handle = VkDevice>> QueryPool for QueryPoolObject<Device> {}
76impl<Device: VkHandle<Handle = VkDevice>> QueryPoolObject<Device> {
77 pub const unsafe fn manage(handle: VkQueryPool, parent: Device) -> Self {
81 Self(handle, parent)
82 }
83
84 pub const fn unmanage(self) -> (VkQueryPool, Device) {
86 let h = self.0;
87 let p = unsafe { core::ptr::read(&self.1) };
88 core::mem::forget(self);
89
90 (h, p)
91 }
92}
93impl<Device: VkHandle<Handle = VkDevice> + Clone> QueryPoolObject<&'_ Device> {
94 #[inline(always)]
96 pub fn clone_parent(self) -> QueryPoolObject<Device> {
97 let r = QueryPoolObject(self.0, self.1.clone());
98 core::mem::forget(self);
99
100 r
101 }
102}
103impl<Device: crate::Device> QueryPoolObject<Device> {
104 #[implements]
111 pub fn new(device: Device, info: &QueryPoolCreateInfo) -> crate::Result<Self> {
112 Ok(unsafe { Self::manage(device.new_query_pool_raw(info, None)?, device) })
113 }
114}
115
116pub enum QueryResult<T> {
117 Err(VkResult),
118 Ready(T),
119 NotReady,
120}
121impl QueryResult<()> {
122 pub(crate) const fn from_vk(r: VkResult) -> Self {
123 match r {
124 VK_NOT_READY => Self::NotReady,
125 r if r.is_err() => Self::Err(r),
126 _ => Self::Ready(()),
127 }
128 }
129}
130impl<T> QueryResult<T> {
131 #[inline(always)]
132 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> QueryResult<U> {
133 match self {
134 Self::Err(r) => QueryResult::Err(r),
135 Self::NotReady => QueryResult::NotReady,
136 Self::Ready(x) => QueryResult::Ready(f(x)),
137 }
138 }
139}
140
141pub trait QueryPool: VkHandle<Handle = VkQueryPool> + DeviceChildHandle {
142 #[implements]
150 #[inline]
151 fn results<T>(
152 &self,
153 offset: u32,
154 sink: &mut [core::mem::MaybeUninit<T>],
155 flags: QueryResultFlags,
156 ) -> QueryResult<()> {
157 unsafe {
158 QueryResult::from_vk(crate::vkfn::get_query_pool_results(
159 self.device_handle(),
160 self.native_ptr(),
161 offset,
162 sink.len() as _,
163 (core::mem::size_of::<T>() * sink.len()) as _,
164 sink.as_mut_ptr() as _,
165 core::mem::size_of::<T>() as _,
166 flags.bits(),
167 ))
168 }
169 }
170
171 #[implements]
179 fn result_array<const N: usize, T>(&self, offset: u32, flags: QueryResultFlags) -> QueryResult<[T; N]> {
180 let mut sink = [const { unsafe { core::mem::MaybeUninit::<T>::uninit().assume_init() } }; N];
181 self.results(
182 offset,
183 unsafe { core::mem::transmute::<&mut [T], &mut [core::mem::MaybeUninit<T>]>(&mut sink[..]) },
184 flags,
185 )
186 .map(move |_| sink)
187 }
188
189 #[implements("alloc")]
197 fn results64_alloc(&self, query_range: core::ops::Range<u32>, flags: QueryResultFlags) -> QueryResult<Vec<u64>> {
198 let mut v = Vec::with_capacity(query_range.len());
199 self.results(
200 query_range.start,
201 &mut v.spare_capacity_mut()[..query_range.len()],
202 flags | QueryResultFlags::WIDE,
203 )
204 .map(|_| {
205 unsafe {
206 v.set_len(query_range.len());
207 }
208 v
209 })
210 }
211
212 #[implements("alloc")]
220 fn results32_alloc(&self, query_range: core::ops::Range<u32>, flags: QueryResultFlags) -> QueryResult<Vec<u32>> {
221 let mut v = Vec::with_capacity(query_range.len());
222 self.results(
223 query_range.start,
224 &mut v.spare_capacity_mut()[..query_range.len()],
225 flags,
226 )
227 .map(move |_| {
228 unsafe {
229 v.set_len(query_range.len());
230 }
231 v
232 })
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
238#[bitflags_newtype]
239pub struct QueryPipelineStatisticFlags(pub VkQueryPipelineStatisticFlags);
240impl QueryPipelineStatisticFlags {
241 pub const INPUT_ASSEMBLY_VERTICES: Self =
243 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT);
244 pub const INPUT_ASSEMBLY_PRIMITIVES: Self =
246 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT);
247 pub const VERTEX_SHADER_INVOCATIONS: Self =
249 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT);
250 pub const GEOMETRY_SHADER_INVOCATIONS: Self =
252 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT);
253 pub const GEOMETRY_SHADER_PRIMITIVES: Self =
255 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT);
256 pub const CLIPPING_INVOCATIONS: Self =
258 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT);
259 pub const CLIPPING_PRIMITIVES: Self =
261 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT);
262 pub const FRAGMENT_SHADER_INVOCATIONS: Self =
264 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT);
265 pub const TESSELLATION_CONTROL_SHADER_PATCHES: Self =
267 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT);
268 pub const TESSELLATION_EVALUATION_SHADER_INVOCATIONS: Self =
270 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT);
271 pub const COMPUTE_SHADER_INVOCATIONS: Self =
273 QueryPipelineStatisticFlags(VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT);
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq)]
278#[bitflags_newtype]
279pub struct QueryResultFlags(VkQueryResultFlags);
280impl QueryResultFlags {
281 pub const EMPTY: Self = QueryResultFlags(0);
283 pub const WIDE: Self = QueryResultFlags(VK_QUERY_RESULT_64_BIT);
285 pub const WAIT: Self = QueryResultFlags(VK_QUERY_RESULT_WAIT_BIT);
287 pub const WITH_AVAILABILITY: Self = QueryResultFlags(VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
289 pub const PARTIAL: Self = QueryResultFlags(VK_QUERY_RESULT_PARTIAL_BIT);
291}