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::{ 17 buffer::BufferContents, 18 device::{Device, DeviceOwned}, 19 macros::{impl_id_counter, vulkan_bitflags}, 20 DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject, 21 }; 22 use std::{ 23 error::Error, 24 ffi::c_void, 25 fmt::{Display, Error as FmtError, Formatter}, 26 mem::{size_of_val, MaybeUninit}, 27 num::NonZeroU64, 28 ops::Range, 29 ptr, 30 sync::Arc, 31 }; 32 33 /// A collection of one or more queries of a particular type. 34 #[derive(Debug)] 35 pub struct QueryPool { 36 handle: ash::vk::QueryPool, 37 device: Arc<Device>, 38 id: NonZeroU64, 39 40 query_type: QueryType, 41 query_count: u32, 42 } 43 44 impl QueryPool { 45 /// Creates a new `QueryPool`. 46 /// 47 /// # Panics 48 /// 49 /// - Panics if `create_info.query_count` is `0`. new( device: Arc<Device>, create_info: QueryPoolCreateInfo, ) -> Result<Arc<QueryPool>, QueryPoolCreationError>50 pub fn new( 51 device: Arc<Device>, 52 create_info: QueryPoolCreateInfo, 53 ) -> Result<Arc<QueryPool>, QueryPoolCreationError> { 54 let QueryPoolCreateInfo { 55 query_type, 56 query_count, 57 _ne: _, 58 } = create_info; 59 60 // VUID-VkQueryPoolCreateInfo-queryCount-02763 61 assert!(query_count != 0); 62 63 let pipeline_statistics = match query_type { 64 QueryType::PipelineStatistics(flags) => { 65 // VUID-VkQueryPoolCreateInfo-queryType-00791 66 if !device.enabled_features().pipeline_statistics_query { 67 return Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled); 68 } 69 70 // VUID-VkQueryPoolCreateInfo-queryType-00792 71 flags.into() 72 } 73 QueryType::Occlusion | QueryType::Timestamp => { 74 ash::vk::QueryPipelineStatisticFlags::empty() 75 } 76 }; 77 78 let create_info = ash::vk::QueryPoolCreateInfo { 79 flags: ash::vk::QueryPoolCreateFlags::empty(), 80 query_type: query_type.into(), 81 query_count, 82 pipeline_statistics, 83 ..Default::default() 84 }; 85 86 let handle = unsafe { 87 let fns = device.fns(); 88 let mut output = MaybeUninit::uninit(); 89 (fns.v1_0.create_query_pool)( 90 device.handle(), 91 &create_info, 92 ptr::null(), 93 output.as_mut_ptr(), 94 ) 95 .result() 96 .map_err(VulkanError::from)?; 97 output.assume_init() 98 }; 99 100 Ok(Arc::new(QueryPool { 101 handle, 102 device, 103 id: Self::next_id(), 104 query_type, 105 query_count, 106 })) 107 } 108 109 /// Creates a new `QueryPool` from a raw object handle. 110 /// 111 /// # Safety 112 /// 113 /// - `handle` must be a valid Vulkan object handle created from `device`. 114 /// - `create_info` must match the info used to create the object. 115 #[inline] from_handle( device: Arc<Device>, handle: ash::vk::QueryPool, create_info: QueryPoolCreateInfo, ) -> Arc<QueryPool>116 pub unsafe fn from_handle( 117 device: Arc<Device>, 118 handle: ash::vk::QueryPool, 119 create_info: QueryPoolCreateInfo, 120 ) -> Arc<QueryPool> { 121 let QueryPoolCreateInfo { 122 query_type, 123 query_count, 124 _ne: _, 125 } = create_info; 126 127 Arc::new(QueryPool { 128 handle, 129 device, 130 id: Self::next_id(), 131 query_type, 132 query_count, 133 }) 134 } 135 136 /// Returns the query type of the pool. 137 #[inline] query_type(&self) -> QueryType138 pub fn query_type(&self) -> QueryType { 139 self.query_type 140 } 141 142 /// Returns the number of query slots of this query pool. 143 #[inline] query_count(&self) -> u32144 pub fn query_count(&self) -> u32 { 145 self.query_count 146 } 147 148 /// Returns a reference to a single query slot, or `None` if the index is out of range. 149 #[inline] query(&self, index: u32) -> Option<Query<'_>>150 pub fn query(&self, index: u32) -> Option<Query<'_>> { 151 if index < self.query_count { 152 Some(Query { pool: self, index }) 153 } else { 154 None 155 } 156 } 157 158 /// Returns a reference to a range of queries, or `None` if out of range. 159 /// 160 /// # Panics 161 /// 162 /// - Panics if the range is empty. 163 #[inline] queries_range(&self, range: Range<u32>) -> Option<QueriesRange<'_>>164 pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange<'_>> { 165 assert!(!range.is_empty()); 166 167 if range.end <= self.query_count { 168 Some(QueriesRange { pool: self, range }) 169 } else { 170 None 171 } 172 } 173 } 174 175 impl Drop for QueryPool { 176 #[inline] drop(&mut self)177 fn drop(&mut self) { 178 unsafe { 179 let fns = self.device.fns(); 180 (fns.v1_0.destroy_query_pool)(self.device.handle(), self.handle, ptr::null()); 181 } 182 } 183 } 184 185 unsafe impl VulkanObject for QueryPool { 186 type Handle = ash::vk::QueryPool; 187 188 #[inline] handle(&self) -> Self::Handle189 fn handle(&self) -> Self::Handle { 190 self.handle 191 } 192 } 193 194 unsafe impl DeviceOwned for QueryPool { 195 #[inline] device(&self) -> &Arc<Device>196 fn device(&self) -> &Arc<Device> { 197 &self.device 198 } 199 } 200 201 impl_id_counter!(QueryPool); 202 203 /// Parameters to create a new `QueryPool`. 204 #[derive(Clone, Debug)] 205 pub struct QueryPoolCreateInfo { 206 /// The type of query that the pool should be for. 207 /// 208 /// There is no default value. 209 pub query_type: QueryType, 210 211 /// The number of queries to create in the pool. 212 /// 213 /// The default value is `0`, which must be overridden. 214 pub query_count: u32, 215 216 pub _ne: crate::NonExhaustive, 217 } 218 219 impl QueryPoolCreateInfo { 220 /// Returns a `QueryPoolCreateInfo` with the specified `query_type`. 221 #[inline] query_type(query_type: QueryType) -> Self222 pub fn query_type(query_type: QueryType) -> Self { 223 Self { 224 query_type, 225 query_count: 0, 226 _ne: crate::NonExhaustive(()), 227 } 228 } 229 } 230 231 /// Error that can happen when creating a query pool. 232 #[derive(Clone, Debug, PartialEq, Eq)] 233 pub enum QueryPoolCreationError { 234 /// Not enough memory. 235 OomError(OomError), 236 /// A pipeline statistics pool was requested but the corresponding feature wasn't enabled. 237 PipelineStatisticsQueryFeatureNotEnabled, 238 } 239 240 impl Error for QueryPoolCreationError { source(&self) -> Option<&(dyn Error + 'static)>241 fn source(&self) -> Option<&(dyn Error + 'static)> { 242 match self { 243 QueryPoolCreationError::OomError(err) => Some(err), 244 _ => None, 245 } 246 } 247 } 248 249 impl Display for QueryPoolCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>250 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 251 write!( 252 f, 253 "{}", 254 match self { 255 QueryPoolCreationError::OomError(_) => "not enough memory available", 256 QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled => { 257 "a pipeline statistics pool was requested but the corresponding feature \ 258 wasn't enabled" 259 } 260 } 261 ) 262 } 263 } 264 265 impl From<OomError> for QueryPoolCreationError { from(err: OomError) -> QueryPoolCreationError266 fn from(err: OomError) -> QueryPoolCreationError { 267 QueryPoolCreationError::OomError(err) 268 } 269 } 270 271 impl From<VulkanError> for QueryPoolCreationError { from(err: VulkanError) -> QueryPoolCreationError272 fn from(err: VulkanError) -> QueryPoolCreationError { 273 match err { 274 err @ VulkanError::OutOfHostMemory => { 275 QueryPoolCreationError::OomError(OomError::from(err)) 276 } 277 err @ VulkanError::OutOfDeviceMemory => { 278 QueryPoolCreationError::OomError(OomError::from(err)) 279 } 280 _ => panic!("unexpected error: {:?}", err), 281 } 282 } 283 } 284 285 /// A reference to a single query slot. 286 /// 287 /// This is created through [`QueryPool::query`]. 288 #[derive(Clone, Debug)] 289 pub struct Query<'a> { 290 pool: &'a QueryPool, 291 index: u32, 292 } 293 294 impl<'a> Query<'a> { 295 /// Returns a reference to the query pool. 296 #[inline] pool(&self) -> &'a QueryPool297 pub fn pool(&self) -> &'a QueryPool { 298 self.pool 299 } 300 301 /// Returns the index of the query represented. 302 #[inline] index(&self) -> u32303 pub fn index(&self) -> u32 { 304 self.index 305 } 306 } 307 308 /// A reference to a range of queries. 309 /// 310 /// This is created through [`QueryPool::queries_range`]. 311 #[derive(Clone, Debug)] 312 pub struct QueriesRange<'a> { 313 pool: &'a QueryPool, 314 range: Range<u32>, 315 } 316 317 impl<'a> QueriesRange<'a> { 318 /// Returns a reference to the query pool. 319 #[inline] pool(&self) -> &'a QueryPool320 pub fn pool(&self) -> &'a QueryPool { 321 self.pool 322 } 323 324 /// Returns the range of queries represented. 325 #[inline] range(&self) -> Range<u32>326 pub fn range(&self) -> Range<u32> { 327 self.range.clone() 328 } 329 330 /// Copies the results of this range of queries to a buffer on the CPU. 331 /// 332 /// [`self.pool().ty().result_len()`] will be written for each query in the range, plus 1 extra 333 /// element per query if [`WITH_AVAILABILITY`] is enabled. The provided buffer must be large 334 /// enough to hold the data. 335 /// 336 /// `true` is returned if every result was available and written to the buffer. `false` 337 /// is returned if some results were not yet available; these will not be written to the buffer. 338 /// 339 /// See also [`copy_query_pool_results`]. 340 /// 341 /// [`self.pool().ty().result_len()`]: QueryType::result_len 342 /// [`WITH_AVAILABILITY`]: QueryResultFlags::WITH_AVAILABILITY 343 /// [`copy_query_pool_results`]: crate::command_buffer::AutoCommandBufferBuilder::copy_query_pool_results 344 #[inline] get_results<T>( &self, destination: &mut [T], flags: QueryResultFlags, ) -> Result<bool, GetResultsError> where T: QueryResultElement,345 pub fn get_results<T>( 346 &self, 347 destination: &mut [T], 348 flags: QueryResultFlags, 349 ) -> Result<bool, GetResultsError> 350 where 351 T: QueryResultElement, 352 { 353 let stride = self.check_query_pool_results::<T>( 354 destination.as_ptr() as DeviceSize, 355 destination.len() as DeviceSize, 356 flags, 357 )?; 358 359 let result = unsafe { 360 let fns = self.pool.device.fns(); 361 (fns.v1_0.get_query_pool_results)( 362 self.pool.device.handle(), 363 self.pool.handle(), 364 self.range.start, 365 self.range.end - self.range.start, 366 size_of_val(destination), 367 destination.as_mut_ptr() as *mut c_void, 368 stride, 369 ash::vk::QueryResultFlags::from(flags) | T::FLAG, 370 ) 371 }; 372 373 match result { 374 ash::vk::Result::SUCCESS => Ok(true), 375 ash::vk::Result::NOT_READY => Ok(false), 376 err => Err(VulkanError::from(err).into()), 377 } 378 } 379 check_query_pool_results<T>( &self, buffer_start: DeviceSize, buffer_len: DeviceSize, flags: QueryResultFlags, ) -> Result<DeviceSize, GetResultsError> where T: QueryResultElement,380 pub(crate) fn check_query_pool_results<T>( 381 &self, 382 buffer_start: DeviceSize, 383 buffer_len: DeviceSize, 384 flags: QueryResultFlags, 385 ) -> Result<DeviceSize, GetResultsError> 386 where 387 T: QueryResultElement, 388 { 389 // VUID-vkGetQueryPoolResults-flags-parameter 390 // VUID-vkCmdCopyQueryPoolResults-flags-parameter 391 flags.validate_device(&self.pool.device)?; 392 393 assert!(buffer_len > 0); 394 395 // VUID-vkGetQueryPoolResults-flags-02828 396 // VUID-vkGetQueryPoolResults-flags-00815 397 debug_assert!(buffer_start % std::mem::size_of::<T>() as DeviceSize == 0); 398 399 let count = self.range.end - self.range.start; 400 let per_query_len = self.pool.query_type.result_len() 401 + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize; 402 let required_len = per_query_len * count as DeviceSize; 403 404 // VUID-vkGetQueryPoolResults-dataSize-00817 405 if buffer_len < required_len { 406 return Err(GetResultsError::BufferTooSmall { 407 required_len: required_len as DeviceSize, 408 actual_len: buffer_len as DeviceSize, 409 }); 410 } 411 412 match self.pool.query_type { 413 QueryType::Occlusion => (), 414 QueryType::PipelineStatistics(_) => (), 415 QueryType::Timestamp => { 416 // VUID-vkGetQueryPoolResults-queryType-00818 417 if flags.intersects(QueryResultFlags::PARTIAL) { 418 return Err(GetResultsError::InvalidFlags); 419 } 420 } 421 } 422 423 Ok(per_query_len * std::mem::size_of::<T>() as DeviceSize) 424 } 425 } 426 427 /// Error that can happen when calling [`QueriesRange::get_results`]. 428 #[derive(Clone, Debug, PartialEq, Eq)] 429 pub enum GetResultsError { 430 /// The connection to the device has been lost. 431 DeviceLost, 432 433 /// Not enough memory. 434 OomError(OomError), 435 436 RequirementNotMet { 437 required_for: &'static str, 438 requires_one_of: RequiresOneOf, 439 }, 440 441 /// The buffer is too small for the operation. 442 BufferTooSmall { 443 /// Required number of elements in the buffer. 444 required_len: DeviceSize, 445 /// Actual number of elements in the buffer. 446 actual_len: DeviceSize, 447 }, 448 449 /// The provided flags are not allowed for this type of query. 450 InvalidFlags, 451 } 452 453 impl Error for GetResultsError { source(&self) -> Option<&(dyn Error + 'static)>454 fn source(&self) -> Option<&(dyn Error + 'static)> { 455 match self { 456 Self::OomError(err) => Some(err), 457 _ => None, 458 } 459 } 460 } 461 462 impl Display for GetResultsError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>463 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 464 match self { 465 Self::OomError(_) => write!(f, "not enough memory available"), 466 Self::DeviceLost => write!(f, "the connection to the device has been lost"), 467 Self::RequirementNotMet { 468 required_for, 469 requires_one_of, 470 } => write!( 471 f, 472 "a requirement was not met for: {}; requires one of: {}", 473 required_for, requires_one_of, 474 ), 475 Self::BufferTooSmall { .. } => write!(f, "the buffer is too small for the operation"), 476 Self::InvalidFlags => write!( 477 f, 478 "the provided flags are not allowed for this type of query" 479 ), 480 } 481 } 482 } 483 484 impl From<VulkanError> for GetResultsError { from(err: VulkanError) -> Self485 fn from(err: VulkanError) -> Self { 486 match err { 487 VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory => { 488 Self::OomError(OomError::from(err)) 489 } 490 VulkanError::DeviceLost => Self::DeviceLost, 491 _ => panic!("unexpected error: {:?}", err), 492 } 493 } 494 } 495 496 impl From<OomError> for GetResultsError { from(err: OomError) -> Self497 fn from(err: OomError) -> Self { 498 Self::OomError(err) 499 } 500 } 501 502 impl From<RequirementNotMet> for GetResultsError { from(err: RequirementNotMet) -> Self503 fn from(err: RequirementNotMet) -> Self { 504 Self::RequirementNotMet { 505 required_for: err.required_for, 506 requires_one_of: err.requires_one_of, 507 } 508 } 509 } 510 511 /// A trait for elements of buffers that can be used as a destination for query results. 512 /// 513 /// # Safety 514 /// This is implemented for `u32` and `u64`. Unless you really know what you're doing, you should 515 /// not implement this trait for any other type. 516 pub unsafe trait QueryResultElement: BufferContents + Sized { 517 const FLAG: ash::vk::QueryResultFlags; 518 } 519 520 unsafe impl QueryResultElement for u32 { 521 const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::empty(); 522 } 523 524 unsafe impl QueryResultElement for u64 { 525 const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::TYPE_64; 526 } 527 528 /// The type of query that a query pool should perform. 529 #[derive(Debug, Copy, Clone)] 530 pub enum QueryType { 531 /// Tracks the number of samples that pass per-fragment tests (e.g. the depth test). 532 Occlusion, 533 /// Tracks statistics on pipeline invocations and their input data. 534 PipelineStatistics(QueryPipelineStatisticFlags), 535 /// Writes timestamps at chosen points in a command buffer. 536 Timestamp, 537 } 538 539 impl QueryType { 540 /// Returns the number of [`QueryResultElement`]s that are needed to hold the result of a 541 /// single query of this type. 542 /// 543 /// - For [`Occlusion`] and [`Timestamp`] queries, this returns 1. 544 /// - For [`PipelineStatistics`] queries, this returns the number of statistics flags enabled. 545 /// 546 /// If the results are retrieved with [`WITH_AVAILABILITY`] enabled, then an additional element 547 /// is required per query. 548 /// 549 /// [`Occlusion`]: QueryType::Occlusion 550 /// [`Timestamp`]: QueryType::Timestamp 551 /// [`PipelineStatistics`]: QueryType::PipelineStatistics 552 /// [`WITH_AVAILABILITY`]: QueryResultFlags::WITH_AVAILABILITY 553 #[inline] result_len(self) -> DeviceSize554 pub const fn result_len(self) -> DeviceSize { 555 match self { 556 Self::Occlusion | Self::Timestamp => 1, 557 Self::PipelineStatistics(flags) => flags.count() as DeviceSize, 558 } 559 } 560 } 561 562 impl From<QueryType> for ash::vk::QueryType { 563 #[inline] from(value: QueryType) -> Self564 fn from(value: QueryType) -> Self { 565 match value { 566 QueryType::Occlusion => ash::vk::QueryType::OCCLUSION, 567 QueryType::PipelineStatistics(_) => ash::vk::QueryType::PIPELINE_STATISTICS, 568 QueryType::Timestamp => ash::vk::QueryType::TIMESTAMP, 569 } 570 } 571 } 572 573 vulkan_bitflags! { 574 #[non_exhaustive] 575 576 /// Flags that control how a query is to be executed. 577 QueryControlFlags = QueryControlFlags(u32); 578 579 /// For occlusion queries, specifies that the result must reflect the exact number of 580 /// tests passed. If not enabled, the query may return a result of 1 even if more fragments 581 /// passed the test. 582 PRECISE = PRECISE, 583 } 584 585 vulkan_bitflags! { 586 #[non_exhaustive] 587 588 /// For pipeline statistics queries, the statistics that should be gathered. 589 QueryPipelineStatisticFlags impl { 590 /// Returns `true` if `self` contains any flags referring to compute operations. 591 #[inline] 592 pub const fn is_compute(self) -> bool { 593 self.intersects(QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS) 594 } 595 596 /// Returns `true` if `self` contains any flags referring to graphics operations. 597 #[inline] 598 pub const fn is_graphics(self) -> bool { 599 self.intersects( 600 (QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES) 601 .union(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES) 602 .union(QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS) 603 .union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_INVOCATIONS) 604 .union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES) 605 .union(QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS) 606 .union(QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES) 607 .union(QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS) 608 .union(QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES) 609 .union(QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS), 610 ) 611 } 612 } 613 = QueryPipelineStatisticFlags(u32); 614 615 /// Count the number of vertices processed by the input assembly. 616 INPUT_ASSEMBLY_VERTICES = INPUT_ASSEMBLY_VERTICES, 617 618 /// Count the number of primitives processed by the input assembly. 619 INPUT_ASSEMBLY_PRIMITIVES = INPUT_ASSEMBLY_PRIMITIVES, 620 621 /// Count the number of times a vertex shader is invoked. 622 VERTEX_SHADER_INVOCATIONS = VERTEX_SHADER_INVOCATIONS, 623 624 /// Count the number of times a geometry shader is invoked. 625 GEOMETRY_SHADER_INVOCATIONS = GEOMETRY_SHADER_INVOCATIONS, 626 627 /// Count the number of primitives generated by geometry shaders. 628 GEOMETRY_SHADER_PRIMITIVES = GEOMETRY_SHADER_PRIMITIVES, 629 630 /// Count the number of times the clipping stage is invoked on a primitive. 631 CLIPPING_INVOCATIONS = CLIPPING_INVOCATIONS, 632 633 /// Count the number of primitives that are output by the clipping stage. 634 CLIPPING_PRIMITIVES = CLIPPING_PRIMITIVES, 635 636 /// Count the number of times a fragment shader is invoked. 637 FRAGMENT_SHADER_INVOCATIONS = FRAGMENT_SHADER_INVOCATIONS, 638 639 /// Count the number of patches processed by a tessellation control shader. 640 TESSELLATION_CONTROL_SHADER_PATCHES = TESSELLATION_CONTROL_SHADER_PATCHES, 641 642 /// Count the number of times a tessellation evaluation shader is invoked. 643 TESSELLATION_EVALUATION_SHADER_INVOCATIONS = TESSELLATION_EVALUATION_SHADER_INVOCATIONS, 644 645 /// Count the number of times a compute shader is invoked. 646 COMPUTE_SHADER_INVOCATIONS = COMPUTE_SHADER_INVOCATIONS, 647 648 /* TODO: enable 649 // TODO: document 650 TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_NV { 651 device_extensions: [nv_mesh_shader], 652 },*/ 653 654 /* TODO: enable 655 // TODO: document 656 MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_NV { 657 device_extensions: [nv_mesh_shader], 658 },*/ 659 } 660 661 vulkan_bitflags! { 662 #[non_exhaustive] 663 664 /// Flags to control how the results of a query should be retrieved. 665 /// 666 /// `VK_QUERY_RESULT_64_BIT` is not included, as it is determined automatically via the 667 /// [`QueryResultElement`] trait. 668 QueryResultFlags = QueryResultFlags(u32); 669 670 /// Wait for the results to become available before writing the results. 671 WAIT = WAIT, 672 673 /// Write an additional element to the end of each query's results, indicating the availability 674 /// of the results: 675 /// - Nonzero: The results are available, and have been written to the element(s) preceding. 676 /// - Zero: The results are not yet available, and have not been written. 677 WITH_AVAILABILITY = WITH_AVAILABILITY, 678 679 /// Allow writing partial results to the buffer, instead of waiting until they are fully 680 /// available. 681 PARTIAL = PARTIAL, 682 683 /* TODO: enable 684 // TODO: document 685 WITH_STATUS = WITH_STATUS_KHR { 686 device_extensions: [khr_video_queue], 687 },*/ 688 } 689 690 #[cfg(test)] 691 mod tests { 692 use super::QueryPoolCreateInfo; 693 use crate::query::{QueryPipelineStatisticFlags, QueryPool, QueryPoolCreationError, QueryType}; 694 695 #[test] pipeline_statistics_feature()696 fn pipeline_statistics_feature() { 697 let (device, _) = gfx_dev_and_queue!(); 698 let query_type = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::empty()); 699 match QueryPool::new( 700 device, 701 QueryPoolCreateInfo { 702 query_count: 256, 703 ..QueryPoolCreateInfo::query_type(query_type) 704 }, 705 ) { 706 Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => (), 707 _ => panic!(), 708 }; 709 } 710 } 711