• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Gather information about rendering, held in query pools.
11 //!
12 //! In Vulkan, queries are not created individually. Instead you manipulate **query pools**, which
13 //! represent a collection of queries. Whenever you use a query, you have to specify both the query
14 //! pool and the slot id within that query pool.
15 
16 use crate::check_errors;
17 use crate::device::Device;
18 use crate::device::DeviceOwned;
19 use crate::DeviceSize;
20 use crate::Error;
21 use crate::OomError;
22 use crate::Success;
23 use crate::VulkanObject;
24 use std::error;
25 use std::ffi::c_void;
26 use std::fmt;
27 use std::mem::MaybeUninit;
28 use std::ops::Range;
29 use std::ptr;
30 use std::sync::Arc;
31 
32 /// A collection of one or more queries of a particular type.
33 #[derive(Debug)]
34 pub struct QueryPool {
35     pool: ash::vk::QueryPool,
36     device: Arc<Device>,
37     num_slots: u32,
38     ty: QueryType,
39 }
40 
41 impl QueryPool {
42     /// Builds a new query pool.
new( device: Arc<Device>, ty: QueryType, num_slots: u32, ) -> Result<QueryPool, QueryPoolCreationError>43     pub fn new(
44         device: Arc<Device>,
45         ty: QueryType,
46         num_slots: u32,
47     ) -> Result<QueryPool, QueryPoolCreationError> {
48         let statistics = match ty {
49             QueryType::PipelineStatistics(flags) => {
50                 if !device.enabled_features().pipeline_statistics_query {
51                     return Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled);
52                 }
53 
54                 flags.into()
55             }
56             QueryType::Occlusion | QueryType::Timestamp => {
57                 ash::vk::QueryPipelineStatisticFlags::empty()
58             }
59         };
60 
61         let pool = unsafe {
62             let infos = ash::vk::QueryPoolCreateInfo {
63                 flags: ash::vk::QueryPoolCreateFlags::empty(),
64                 query_type: ty.into(),
65                 query_count: num_slots,
66                 pipeline_statistics: statistics,
67                 ..Default::default()
68             };
69 
70             let mut output = MaybeUninit::uninit();
71             let fns = device.fns();
72             check_errors(fns.v1_0.create_query_pool(
73                 device.internal_object(),
74                 &infos,
75                 ptr::null(),
76                 output.as_mut_ptr(),
77             ))?;
78             output.assume_init()
79         };
80 
81         Ok(QueryPool {
82             pool,
83             device,
84             num_slots,
85             ty,
86         })
87     }
88 
89     /// Returns the [`QueryType`] that this query pool was created with.
90     #[inline]
ty(&self) -> QueryType91     pub fn ty(&self) -> QueryType {
92         self.ty
93     }
94 
95     /// Returns the number of query slots of this query pool.
96     #[inline]
num_slots(&self) -> u3297     pub fn num_slots(&self) -> u32 {
98         self.num_slots
99     }
100 
101     /// Returns a reference to a single query slot, or `None` if the index is out of range.
102     #[inline]
query(&self, index: u32) -> Option<Query>103     pub fn query(&self, index: u32) -> Option<Query> {
104         if index < self.num_slots() {
105             Some(Query { pool: self, index })
106         } else {
107             None
108         }
109     }
110 
111     /// Returns a reference to a range of queries, or `None` if out of range.
112     ///
113     /// # Panic
114     ///
115     /// Panics if the range is empty.
116     #[inline]
queries_range(&self, range: Range<u32>) -> Option<QueriesRange>117     pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange> {
118         assert!(!range.is_empty());
119 
120         if range.end <= self.num_slots() {
121             Some(QueriesRange { pool: self, range })
122         } else {
123             None
124         }
125     }
126 }
127 
128 unsafe impl VulkanObject for QueryPool {
129     type Object = ash::vk::QueryPool;
130 
131     #[inline]
internal_object(&self) -> ash::vk::QueryPool132     fn internal_object(&self) -> ash::vk::QueryPool {
133         self.pool
134     }
135 }
136 
137 unsafe impl DeviceOwned for QueryPool {
138     #[inline]
device(&self) -> &Arc<Device>139     fn device(&self) -> &Arc<Device> {
140         &self.device
141     }
142 }
143 
144 impl Drop for QueryPool {
145     #[inline]
drop(&mut self)146     fn drop(&mut self) {
147         unsafe {
148             let fns = self.device.fns();
149             fns.v1_0
150                 .destroy_query_pool(self.device.internal_object(), self.pool, ptr::null());
151         }
152     }
153 }
154 
155 /// Error that can happen when creating a query pool.
156 #[derive(Clone, Debug, PartialEq, Eq)]
157 pub enum QueryPoolCreationError {
158     /// Not enough memory.
159     OomError(OomError),
160     /// A pipeline statistics pool was requested but the corresponding feature wasn't enabled.
161     PipelineStatisticsQueryFeatureNotEnabled,
162 }
163 
164 impl error::Error for QueryPoolCreationError {
165     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>166     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
167         match *self {
168             QueryPoolCreationError::OomError(ref err) => Some(err),
169             _ => None,
170         }
171     }
172 }
173 
174 impl fmt::Display for QueryPoolCreationError {
175     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>176     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
177         write!(
178             fmt,
179             "{}",
180             match *self {
181                 QueryPoolCreationError::OomError(_) => "not enough memory available",
182                 QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled => {
183                     "a pipeline statistics pool was requested but the corresponding feature \
184                  wasn't enabled"
185                 }
186             }
187         )
188     }
189 }
190 
191 impl From<OomError> for QueryPoolCreationError {
192     #[inline]
from(err: OomError) -> QueryPoolCreationError193     fn from(err: OomError) -> QueryPoolCreationError {
194         QueryPoolCreationError::OomError(err)
195     }
196 }
197 
198 impl From<Error> for QueryPoolCreationError {
199     #[inline]
from(err: Error) -> QueryPoolCreationError200     fn from(err: Error) -> QueryPoolCreationError {
201         match err {
202             err @ Error::OutOfHostMemory => QueryPoolCreationError::OomError(OomError::from(err)),
203             err @ Error::OutOfDeviceMemory => QueryPoolCreationError::OomError(OomError::from(err)),
204             _ => panic!("unexpected error: {:?}", err),
205         }
206     }
207 }
208 
209 /// A reference to a single query slot.
210 ///
211 /// This is created through [`QueryPool::query`].
212 #[derive(Clone, Debug)]
213 pub struct Query<'a> {
214     pool: &'a QueryPool,
215     index: u32,
216 }
217 
218 impl<'a> Query<'a> {
219     /// Returns a reference to the query pool.
220     #[inline]
pool(&self) -> &'a QueryPool221     pub fn pool(&self) -> &'a QueryPool {
222         &self.pool
223     }
224 
225     /// Returns the index of the query represented.
226     #[inline]
index(&self) -> u32227     pub fn index(&self) -> u32 {
228         self.index
229     }
230 }
231 
232 /// A reference to a range of queries.
233 ///
234 /// This is created through [`QueryPool::queries_range`].
235 #[derive(Clone, Debug)]
236 pub struct QueriesRange<'a> {
237     pool: &'a QueryPool,
238     range: Range<u32>,
239 }
240 
241 impl<'a> QueriesRange<'a> {
242     /// Returns a reference to the query pool.
243     #[inline]
pool(&self) -> &'a QueryPool244     pub fn pool(&self) -> &'a QueryPool {
245         &self.pool
246     }
247 
248     /// Returns the range of queries represented.
249     #[inline]
range(&self) -> Range<u32>250     pub fn range(&self) -> Range<u32> {
251         self.range.clone()
252     }
253 
254     /// Copies the results of this range of queries to a buffer on the CPU.
255     ///
256     /// [`self.pool().ty().result_size()`](QueryType::result_size) elements
257     /// will be written for each query in the range, plus 1 extra element per query if
258     /// [`QueryResultFlags::with_availability`] is enabled.
259     /// The provided buffer must be large enough to hold the data.
260     ///
261     /// `true` is returned if every result was available and written to the buffer. `false`
262     /// is returned if some results were not yet available; these will not be written to the buffer.
263     ///
264     /// See also [`copy_query_pool_results`](crate::command_buffer::AutoCommandBufferBuilder::copy_query_pool_results).
get_results<T>( &self, destination: &mut [T], flags: QueryResultFlags, ) -> Result<bool, GetResultsError> where T: QueryResultElement,265     pub fn get_results<T>(
266         &self,
267         destination: &mut [T],
268         flags: QueryResultFlags,
269     ) -> Result<bool, GetResultsError>
270     where
271         T: QueryResultElement,
272     {
273         let stride = self.check_query_pool_results::<T>(
274             destination.as_ptr() as DeviceSize,
275             destination.len() as DeviceSize,
276             flags,
277         )?;
278 
279         let result = unsafe {
280             let fns = self.pool.device.fns();
281             check_errors(fns.v1_0.get_query_pool_results(
282                 self.pool.device.internal_object(),
283                 self.pool.internal_object(),
284                 self.range.start,
285                 self.range.end - self.range.start,
286                 std::mem::size_of_val(destination),
287                 destination.as_mut_ptr() as *mut c_void,
288                 stride,
289                 ash::vk::QueryResultFlags::from(flags) | T::FLAG,
290             ))?
291         };
292 
293         Ok(match result {
294             Success::Success => true,
295             Success::NotReady => false,
296             s => panic!("unexpected success value: {:?}", s),
297         })
298     }
299 
check_query_pool_results<T>( &self, buffer_start: DeviceSize, buffer_len: DeviceSize, flags: QueryResultFlags, ) -> Result<DeviceSize, GetResultsError> where T: QueryResultElement,300     pub(crate) fn check_query_pool_results<T>(
301         &self,
302         buffer_start: DeviceSize,
303         buffer_len: DeviceSize,
304         flags: QueryResultFlags,
305     ) -> Result<DeviceSize, GetResultsError>
306     where
307         T: QueryResultElement,
308     {
309         assert!(buffer_len > 0);
310         debug_assert!(buffer_start % std::mem::size_of::<T>() as DeviceSize == 0);
311 
312         let count = self.range.end - self.range.start;
313         let per_query_len = self.pool.ty.result_size() + flags.with_availability as DeviceSize;
314         let required_len = per_query_len * count as DeviceSize;
315 
316         if buffer_len < required_len {
317             return Err(GetResultsError::BufferTooSmall {
318                 required_len: required_len as DeviceSize,
319                 actual_len: buffer_len as DeviceSize,
320             });
321         }
322 
323         match self.pool.ty {
324             QueryType::Occlusion => (),
325             QueryType::PipelineStatistics(_) => (),
326             QueryType::Timestamp => {
327                 if flags.partial {
328                     return Err(GetResultsError::InvalidFlags);
329                 }
330             }
331         }
332 
333         Ok(per_query_len * std::mem::size_of::<T>() as DeviceSize)
334     }
335 }
336 
337 /// Error that can happen when calling [`QueriesRange::get_results`].
338 #[derive(Clone, Debug, PartialEq, Eq)]
339 pub enum GetResultsError {
340     /// The buffer is too small for the operation.
341     BufferTooSmall {
342         /// Required number of elements in the buffer.
343         required_len: DeviceSize,
344         /// Actual number of elements in the buffer.
345         actual_len: DeviceSize,
346     },
347     /// The connection to the device has been lost.
348     DeviceLost,
349     /// The provided flags are not allowed for this type of query.
350     InvalidFlags,
351     /// Not enough memory.
352     OomError(OomError),
353 }
354 
355 impl From<Error> for GetResultsError {
356     #[inline]
from(err: Error) -> Self357     fn from(err: Error) -> Self {
358         match err {
359             Error::OutOfHostMemory | Error::OutOfDeviceMemory => {
360                 Self::OomError(OomError::from(err))
361             }
362             Error::DeviceLost => Self::DeviceLost,
363             _ => panic!("unexpected error: {:?}", err),
364         }
365     }
366 }
367 
368 impl From<OomError> for GetResultsError {
369     #[inline]
from(err: OomError) -> Self370     fn from(err: OomError) -> Self {
371         Self::OomError(err)
372     }
373 }
374 
375 impl fmt::Display for GetResultsError {
376     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>377     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
378         write!(
379             fmt,
380             "{}",
381             match *self {
382                 Self::BufferTooSmall { .. } => {
383                     "the buffer is too small for the operation"
384                 }
385                 Self::DeviceLost => "the connection to the device has been lost",
386                 Self::InvalidFlags => {
387                     "the provided flags are not allowed for this type of query"
388                 }
389                 Self::OomError(_) => "not enough memory available",
390             }
391         )
392     }
393 }
394 
395 impl error::Error for GetResultsError {
396     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>397     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
398         match *self {
399             Self::OomError(ref err) => Some(err),
400             _ => None,
401         }
402     }
403 }
404 
405 /// A trait for elements of buffers that can be used as a destination for query results.
406 ///
407 /// # Safety
408 /// This is implemented for `u32` and `u64`. Unless you really know what you're doing, you should
409 /// not implement this trait for any other type.
410 pub unsafe trait QueryResultElement {
411     const FLAG: ash::vk::QueryResultFlags;
412 }
413 
414 unsafe impl QueryResultElement for u32 {
415     const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::empty();
416 }
417 
418 unsafe impl QueryResultElement for u64 {
419     const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::TYPE_64;
420 }
421 
422 /// The type of query that a query pool should perform.
423 #[derive(Debug, Copy, Clone)]
424 pub enum QueryType {
425     /// Tracks the number of samples that pass per-fragment tests (e.g. the depth test).
426     Occlusion,
427     /// Tracks statistics on pipeline invocations and their input data.
428     PipelineStatistics(QueryPipelineStatisticFlags),
429     /// Writes timestamps at chosen points in a command buffer.
430     Timestamp,
431 }
432 
433 impl QueryType {
434     /// Returns the number of [`QueryResultElement`]s that are needed to hold the result of a
435     /// single query of this type.
436     ///
437     /// - For `Occlusion` and `Timestamp` queries, this returns 1.
438     /// - For `PipelineStatistics` queries, this returns the number of statistics flags enabled.
439     ///
440     /// If the results are retrieved with [`QueryResultFlags::with_availability`] enabled, then
441     /// an additional element is required per query.
442     #[inline]
result_size(&self) -> DeviceSize443     pub const fn result_size(&self) -> DeviceSize {
444         match self {
445             Self::Occlusion | Self::Timestamp => 1,
446             Self::PipelineStatistics(flags) => flags.count(),
447         }
448     }
449 }
450 
451 impl From<QueryType> for ash::vk::QueryType {
452     #[inline]
from(value: QueryType) -> Self453     fn from(value: QueryType) -> Self {
454         match value {
455             QueryType::Occlusion => ash::vk::QueryType::OCCLUSION,
456             QueryType::PipelineStatistics(_) => ash::vk::QueryType::PIPELINE_STATISTICS,
457             QueryType::Timestamp => ash::vk::QueryType::TIMESTAMP,
458         }
459     }
460 }
461 
462 /// Flags that control how a query is to be executed.
463 #[derive(Clone, Copy, Debug, Default)]
464 pub struct QueryControlFlags {
465     /// For occlusion queries, specifies that the result must reflect the exact number of
466     /// tests passed. If not enabled, the query may return a result of 1 even if more fragments
467     /// passed the test.
468     pub precise: bool,
469 }
470 
471 impl From<QueryControlFlags> for ash::vk::QueryControlFlags {
472     #[inline]
from(value: QueryControlFlags) -> Self473     fn from(value: QueryControlFlags) -> Self {
474         let mut result = ash::vk::QueryControlFlags::empty();
475         if value.precise {
476             result |= ash::vk::QueryControlFlags::PRECISE;
477         }
478         result
479     }
480 }
481 
482 /// For pipeline statistics queries, the statistics that should be gathered.
483 #[derive(Clone, Copy, Debug, Default)]
484 pub struct QueryPipelineStatisticFlags {
485     /// Count the number of vertices processed by the input assembly.
486     pub input_assembly_vertices: bool,
487     /// Count the number of primitives processed by the input assembly.
488     pub input_assembly_primitives: bool,
489     /// Count the number of times a vertex shader is invoked.
490     pub vertex_shader_invocations: bool,
491     /// Count the number of times a geometry shader is invoked.
492     pub geometry_shader_invocations: bool,
493     /// Count the number of primitives generated by geometry shaders.
494     pub geometry_shader_primitives: bool,
495     /// Count the number of times the clipping stage is invoked on a primitive.
496     pub clipping_invocations: bool,
497     /// Count the number of primitives that are output by the clipping stage.
498     pub clipping_primitives: bool,
499     /// Count the number of times a fragment shader is invoked.
500     pub fragment_shader_invocations: bool,
501     /// Count the number of patches processed by a tessellation control shader.
502     pub tessellation_control_shader_patches: bool,
503     /// Count the number of times a tessellation evaluation shader is invoked.
504     pub tessellation_evaluation_shader_invocations: bool,
505     /// Count the number of times a compute shader is invoked.
506     pub compute_shader_invocations: bool,
507 }
508 
509 impl QueryPipelineStatisticFlags {
510     #[inline]
none() -> QueryPipelineStatisticFlags511     pub fn none() -> QueryPipelineStatisticFlags {
512         QueryPipelineStatisticFlags {
513             input_assembly_vertices: false,
514             input_assembly_primitives: false,
515             vertex_shader_invocations: false,
516             geometry_shader_invocations: false,
517             geometry_shader_primitives: false,
518             clipping_invocations: false,
519             clipping_primitives: false,
520             fragment_shader_invocations: false,
521             tessellation_control_shader_patches: false,
522             tessellation_evaluation_shader_invocations: false,
523             compute_shader_invocations: false,
524         }
525     }
526 
527     /// Returns the number of flags that are set to `true`.
528     #[inline]
count(&self) -> DeviceSize529     pub const fn count(&self) -> DeviceSize {
530         let &Self {
531             input_assembly_vertices,
532             input_assembly_primitives,
533             vertex_shader_invocations,
534             geometry_shader_invocations,
535             geometry_shader_primitives,
536             clipping_invocations,
537             clipping_primitives,
538             fragment_shader_invocations,
539             tessellation_control_shader_patches,
540             tessellation_evaluation_shader_invocations,
541             compute_shader_invocations,
542         } = self;
543         input_assembly_vertices as DeviceSize
544             + input_assembly_primitives as DeviceSize
545             + vertex_shader_invocations as DeviceSize
546             + geometry_shader_invocations as DeviceSize
547             + geometry_shader_primitives as DeviceSize
548             + clipping_invocations as DeviceSize
549             + clipping_primitives as DeviceSize
550             + fragment_shader_invocations as DeviceSize
551             + tessellation_control_shader_patches as DeviceSize
552             + tessellation_evaluation_shader_invocations as DeviceSize
553             + compute_shader_invocations as DeviceSize
554     }
555 
556     /// Returns `true` if any flags referring to compute operations are set to `true`.
557     #[inline]
is_compute(&self) -> bool558     pub const fn is_compute(&self) -> bool {
559         let &Self {
560             compute_shader_invocations,
561             ..
562         } = self;
563         compute_shader_invocations
564     }
565 
566     /// Returns `true` if any flags referring to graphics operations are set to `true`.
567     #[inline]
is_graphics(&self) -> bool568     pub const fn is_graphics(&self) -> bool {
569         let &Self {
570             input_assembly_vertices,
571             input_assembly_primitives,
572             vertex_shader_invocations,
573             geometry_shader_invocations,
574             geometry_shader_primitives,
575             clipping_invocations,
576             clipping_primitives,
577             fragment_shader_invocations,
578             tessellation_control_shader_patches,
579             tessellation_evaluation_shader_invocations,
580             ..
581         } = self;
582         input_assembly_vertices
583             || input_assembly_primitives
584             || vertex_shader_invocations
585             || geometry_shader_invocations
586             || geometry_shader_primitives
587             || clipping_invocations
588             || clipping_primitives
589             || fragment_shader_invocations
590             || tessellation_control_shader_patches
591             || tessellation_evaluation_shader_invocations
592     }
593 }
594 
595 impl From<QueryPipelineStatisticFlags> for ash::vk::QueryPipelineStatisticFlags {
from(value: QueryPipelineStatisticFlags) -> ash::vk::QueryPipelineStatisticFlags596     fn from(value: QueryPipelineStatisticFlags) -> ash::vk::QueryPipelineStatisticFlags {
597         let mut result = ash::vk::QueryPipelineStatisticFlags::empty();
598         if value.input_assembly_vertices {
599             result |= ash::vk::QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES;
600         }
601         if value.input_assembly_primitives {
602             result |= ash::vk::QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES;
603         }
604         if value.vertex_shader_invocations {
605             result |= ash::vk::QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS;
606         }
607         if value.geometry_shader_invocations {
608             result |= ash::vk::QueryPipelineStatisticFlags::GEOMETRY_SHADER_INVOCATIONS;
609         }
610         if value.geometry_shader_primitives {
611             result |= ash::vk::QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES;
612         }
613         if value.clipping_invocations {
614             result |= ash::vk::QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS;
615         }
616         if value.clipping_primitives {
617             result |= ash::vk::QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES;
618         }
619         if value.fragment_shader_invocations {
620             result |= ash::vk::QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS;
621         }
622         if value.tessellation_control_shader_patches {
623             result |= ash::vk::QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES;
624         }
625         if value.tessellation_evaluation_shader_invocations {
626             result |=
627                 ash::vk::QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS;
628         }
629         if value.compute_shader_invocations {
630             result |= ash::vk::QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS;
631         }
632         result
633     }
634 }
635 
636 /// Flags to control how the results of a query should be retrieved.
637 ///
638 /// `VK_QUERY_RESULT_64_BIT` is not included, as it is determined automatically via the
639 /// [`QueryResultElement`] trait.
640 #[derive(Clone, Copy, Debug, Default)]
641 pub struct QueryResultFlags {
642     /// Wait for the results to become available before writing the results.
643     pub wait: bool,
644     /// Write an additional element to the end of each query's results, indicating the availability
645     /// of the results:
646     /// - Nonzero: The results are available, and have been written to the element(s) preceding.
647     /// - Zero: The results are not yet available, and have not been written.
648     pub with_availability: bool,
649     /// Allow writing partial results to the buffer, instead of waiting until they are fully
650     /// available.
651     pub partial: bool,
652 }
653 
654 impl From<QueryResultFlags> for ash::vk::QueryResultFlags {
655     #[inline]
from(value: QueryResultFlags) -> Self656     fn from(value: QueryResultFlags) -> Self {
657         let mut result = ash::vk::QueryResultFlags::empty();
658         if value.wait {
659             result |= ash::vk::QueryResultFlags::WAIT;
660         }
661         if value.with_availability {
662             result |= ash::vk::QueryResultFlags::WITH_AVAILABILITY;
663         }
664         if value.partial {
665             result |= ash::vk::QueryResultFlags::PARTIAL;
666         }
667         result
668     }
669 }
670 
671 #[cfg(test)]
672 mod tests {
673     use crate::query::QueryPipelineStatisticFlags;
674     use crate::query::QueryPool;
675     use crate::query::QueryPoolCreationError;
676     use crate::query::QueryType;
677 
678     #[test]
pipeline_statistics_feature()679     fn pipeline_statistics_feature() {
680         let (device, _) = gfx_dev_and_queue!();
681 
682         let ty = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::none());
683         match QueryPool::new(device, ty, 256) {
684             Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => (),
685             _ => panic!(),
686         };
687     }
688 }
689