1use bedrock_vk::{self as brvk, TypedVulkanStructure, VkRawHandle};
2
3use crate::*;
4use derives::{bitflags_newtype, implements};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum QueryType {
9 Occlusion,
11 PipelineStatistics(QueryPipelineStatisticFlags),
13 Timestamp,
15}
16
17#[repr(transparent)]
19#[derive(Clone)]
20pub struct QueryPoolCreateInfo(brvk::VkQueryPoolCreateInfo);
21impl QueryPoolCreateInfo {
22 pub const fn new(query_type: QueryType, count: u32) -> Self {
23 let (qt, ps) = match query_type {
24 QueryType::Occlusion => (brvk::VK_QUERY_TYPE_OCCLUSION, 0),
25 QueryType::PipelineStatistics(st) => (brvk::VK_QUERY_TYPE_PIPELINE_STATISTICS, st.bits()),
26 QueryType::Timestamp => (brvk::VK_QUERY_TYPE_TIMESTAMP, 0),
27 };
28
29 Self(brvk::VkQueryPoolCreateInfo {
30 sType: brvk::VkQueryPoolCreateInfo::TYPE,
31 pNext: core::ptr::null(),
32 flags: 0,
33 queryType: qt,
34 queryCount: count,
35 pipelineStatistics: ps,
36 })
37 }
38
39 pub const unsafe fn from_raw(raw: brvk::VkQueryPoolCreateInfo) -> Self {
43 Self(raw)
44 }
45
46 pub const fn into_raw(self) -> brvk::VkQueryPoolCreateInfo {
47 self.0
48 }
49}
50
51#[derive(VkHandle, VkObject)]
53#[VkObject(type = brvk::VkQueryPool::OBJECT_TYPE)]
54pub struct QueryPoolObject<Device: VkHandle<Handle = brvk::VkDevice>>(brvk::VkQueryPool, Device);
55#[implements]
56impl<Device: VkHandle<Handle = brvk::VkDevice>> Drop for QueryPoolObject<Device> {
57 #[inline(always)]
58 fn drop(&mut self) {
59 unsafe {
60 brvk::fns::destroy_query_pool(self.1.native_ptr(), self.0, core::ptr::null());
61 }
62 }
63}
64unsafe impl<Device: VkHandle<Handle = brvk::VkDevice> + Sync> Sync for QueryPoolObject<Device> {}
65unsafe impl<Device: VkHandle<Handle = brvk::VkDevice> + Send> Send for QueryPoolObject<Device> {}
66impl<Device: VkHandle<Handle = brvk::VkDevice>> DeviceChildHandle for QueryPoolObject<Device> {
67 #[inline(always)]
68 fn device_handle(&self) -> brvk::VkDevice {
69 self.1.native_ptr()
70 }
71}
72impl<Device: crate::Device> DeviceChild for QueryPoolObject<Device> {
73 type ConcreteDevice = Device;
74
75 #[inline(always)]
76 fn device(&self) -> &Self::ConcreteDevice {
77 &self.1
78 }
79}
80impl<Device: VkHandle<Handle = brvk::VkDevice>> QueryPool for QueryPoolObject<Device> {}
81impl<Device: VkHandle<Handle = brvk::VkDevice>> QueryPoolObject<Device> {
82 pub const unsafe fn manage(handle: brvk::VkQueryPool, parent: Device) -> Self {
86 Self(handle, parent)
87 }
88
89 pub const fn unmanage(self) -> (brvk::VkQueryPool, Device) {
91 let h = self.0;
92 let p = unsafe { core::ptr::read(&self.1) };
93 core::mem::forget(self);
94
95 (h, p)
96 }
97}
98impl<Device: VkHandle<Handle = brvk::VkDevice> + Clone> QueryPoolObject<&'_ Device> {
99 #[inline(always)]
101 pub fn clone_parent(self) -> QueryPoolObject<Device> {
102 let r = QueryPoolObject(self.0, self.1.clone());
103 core::mem::forget(self);
104
105 r
106 }
107}
108impl<Device: crate::Device> QueryPoolObject<Device> {
109 #[implements]
116 pub fn new(device: Device, info: &QueryPoolCreateInfo) -> crate::Result<Self> {
117 Ok(unsafe { Self::manage(device.new_query_pool_raw(info, None)?, device) })
118 }
119}
120
121pub enum QueryResult<T> {
122 Err(ResultCode),
123 Ready(T),
124 NotReady,
125}
126impl QueryResult<()> {
127 pub const fn from_vk(r: brvk::VkResult) -> Self {
128 match r {
129 brvk::VK_NOT_READY => Self::NotReady,
130 r => match ResultCode(r) {
131 e if e.is_err() => Self::Err(e),
132 _ => Self::Ready(()),
133 },
134 }
135 }
136}
137impl<T> QueryResult<T> {
138 #[inline(always)]
139 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> QueryResult<U> {
140 match self {
141 Self::Err(r) => QueryResult::Err(r),
142 Self::NotReady => QueryResult::NotReady,
143 Self::Ready(x) => QueryResult::Ready(f(x)),
144 }
145 }
146}
147
148pub trait QueryPool: VkHandle<Handle = brvk::VkQueryPool> + DeviceChildHandle {
149 #[implements]
157 #[inline]
158 fn results<T>(
159 &self,
160 offset: u32,
161 sink: &mut [core::mem::MaybeUninit<T>],
162 flags: QueryResultFlags,
163 ) -> QueryResult<()> {
164 unsafe {
165 QueryResult::from_vk(brvk::fns::get_query_pool_results(
166 self.device_handle(),
167 self.native_ptr(),
168 offset,
169 sink.len() as _,
170 (core::mem::size_of::<T>() * sink.len()) as _,
171 sink.as_mut_ptr() as _,
172 core::mem::size_of::<T>() as _,
173 flags.bits(),
174 ))
175 }
176 }
177
178 #[implements]
186 fn result_array<const N: usize, T>(&self, offset: u32, flags: QueryResultFlags) -> QueryResult<[T; N]>
187 where
188 T: Copy,
189 {
190 let mut sink = [const { core::mem::MaybeUninit::<T>::uninit() }; N];
191 self.results(offset, &mut sink, flags)
192 .map(move |_| core::array::from_fn(|n| unsafe { sink[n].assume_init() }))
193 }
194
195 #[implements("alloc")]
203 fn results64_alloc(&self, query_range: core::ops::Range<u32>, flags: QueryResultFlags) -> QueryResult<Vec<u64>> {
204 let mut v = Vec::with_capacity(query_range.len());
205 self.results(
206 query_range.start,
207 &mut v.spare_capacity_mut()[..query_range.len()],
208 flags | QueryResultFlags::WIDE,
209 )
210 .map(|_| {
211 unsafe {
212 v.set_len(query_range.len());
213 }
214 v
215 })
216 }
217
218 #[implements("alloc")]
226 fn results32_alloc(&self, query_range: core::ops::Range<u32>, flags: QueryResultFlags) -> QueryResult<Vec<u32>> {
227 let mut v = Vec::with_capacity(query_range.len());
228 self.results(
229 query_range.start,
230 &mut v.spare_capacity_mut()[..query_range.len()],
231 flags,
232 )
233 .map(move |_| {
234 unsafe {
235 v.set_len(query_range.len());
236 }
237 v
238 })
239 }
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244#[bitflags_newtype]
245pub struct QueryPipelineStatisticFlags(pub brvk::VkQueryPipelineStatisticFlags);
246impl QueryPipelineStatisticFlags {
247 pub const INPUT_ASSEMBLY_VERTICES: Self =
249 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT);
250 pub const INPUT_ASSEMBLY_PRIMITIVES: Self =
252 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT);
253 pub const VERTEX_SHADER_INVOCATIONS: Self =
255 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT);
256 pub const GEOMETRY_SHADER_INVOCATIONS: Self =
258 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT);
259 pub const GEOMETRY_SHADER_PRIMITIVES: Self =
261 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT);
262 pub const CLIPPING_INVOCATIONS: Self =
264 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT);
265 pub const CLIPPING_PRIMITIVES: Self =
267 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT);
268 pub const FRAGMENT_SHADER_INVOCATIONS: Self =
270 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT);
271 pub const TESSELLATION_CONTROL_SHADER_PATCHES: Self =
273 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT);
274 pub const TESSELLATION_EVALUATION_SHADER_INVOCATIONS: Self =
276 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT);
277 pub const COMPUTE_SHADER_INVOCATIONS: Self =
279 QueryPipelineStatisticFlags(brvk::VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT);
280}
281
282#[derive(Debug, Clone, Copy, PartialEq, Eq)]
284#[bitflags_newtype]
285pub struct QueryResultFlags(brvk::VkQueryResultFlags);
286impl QueryResultFlags {
287 pub const EMPTY: Self = QueryResultFlags(0);
289 pub const WIDE: Self = QueryResultFlags(brvk::VK_QUERY_RESULT_64_BIT);
291 pub const WAIT: Self = QueryResultFlags(brvk::VK_QUERY_RESULT_WAIT_BIT);
293 pub const WITH_AVAILABILITY: Self = QueryResultFlags(brvk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
295 pub const PARTIAL: Self = QueryResultFlags(brvk::VK_QUERY_RESULT_PARTIAL_BIT);
297}