1 // Copyright (c) 2022 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 use crate::{ 11 buffer::{BufferUsage, Subbuffer}, 12 command_buffer::{ 13 allocator::CommandBufferAllocator, 14 auto::QueryState, 15 synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, 16 sys::UnsafeCommandBufferBuilder, 17 AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef, 18 }, 19 device::{DeviceOwned, QueueFlags}, 20 query::{ 21 QueriesRange, Query, QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags, 22 QueryType, 23 }, 24 sync::{AccessFlags, PipelineMemoryAccess, PipelineStage, PipelineStages}, 25 DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject, 26 }; 27 use std::{ 28 error::Error, 29 fmt::{Display, Error as FmtError, Formatter}, 30 mem::size_of, 31 ops::Range, 32 sync::Arc, 33 }; 34 35 /// # Commands related to queries. 36 impl<L, A> AutoCommandBufferBuilder<L, A> 37 where 38 A: CommandBufferAllocator, 39 { 40 /// Begins a query. 41 /// 42 /// The query will be active until [`end_query`](Self::end_query) is called for the same query. 43 /// 44 /// # Safety 45 /// 46 /// The query must be unavailable, ensured by calling 47 /// [`reset_query_pool`](Self::reset_query_pool). begin_query( &mut self, query_pool: Arc<QueryPool>, query: u32, flags: QueryControlFlags, ) -> Result<&mut Self, QueryError>48 pub unsafe fn begin_query( 49 &mut self, 50 query_pool: Arc<QueryPool>, 51 query: u32, 52 flags: QueryControlFlags, 53 ) -> Result<&mut Self, QueryError> { 54 self.validate_begin_query(&query_pool, query, flags)?; 55 56 let ty = query_pool.query_type(); 57 let raw_query_pool = query_pool.handle(); 58 59 self.inner.begin_query(query_pool, query, flags); 60 self.query_state.insert( 61 ty.into(), 62 QueryState { 63 query_pool: raw_query_pool, 64 query, 65 ty, 66 flags, 67 in_subpass: self.render_pass_state.is_some(), 68 }, 69 ); 70 71 Ok(self) 72 } 73 validate_begin_query( &self, query_pool: &QueryPool, query: u32, flags: QueryControlFlags, ) -> Result<(), QueryError>74 fn validate_begin_query( 75 &self, 76 query_pool: &QueryPool, 77 query: u32, 78 flags: QueryControlFlags, 79 ) -> Result<(), QueryError> { 80 let queue_family_properties = self.queue_family_properties(); 81 82 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 83 if !queue_family_properties 84 .queue_flags 85 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 86 { 87 return Err(QueryError::NotSupportedByQueueFamily); 88 } 89 90 let device = self.device(); 91 92 // VUID-vkCmdBeginQuery-flags-parameter 93 flags.validate_device(device)?; 94 95 // VUID-vkCmdBeginQuery-commonparent 96 assert_eq!(device, query_pool.device()); 97 98 // VUID-vkCmdBeginQuery-query-00802 99 query_pool.query(query).ok_or(QueryError::OutOfRange)?; 100 101 match query_pool.query_type() { 102 QueryType::Occlusion => { 103 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 104 // // VUID-vkCmdBeginQuery-queryType-00803 105 if !queue_family_properties 106 .queue_flags 107 .intersects(QueueFlags::GRAPHICS) 108 { 109 return Err(QueryError::NotSupportedByQueueFamily); 110 } 111 112 // VUID-vkCmdBeginQuery-queryType-00800 113 if flags.intersects(QueryControlFlags::PRECISE) 114 && !device.enabled_features().occlusion_query_precise 115 { 116 return Err(QueryError::RequirementNotMet { 117 required_for: "`flags` contains `QueryControlFlags::PRECISE`", 118 requires_one_of: RequiresOneOf { 119 features: &["occlusion_query_precise"], 120 ..Default::default() 121 }, 122 }); 123 } 124 } 125 QueryType::PipelineStatistics(statistic_flags) => { 126 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 127 // VUID-vkCmdBeginQuery-queryType-00804 128 // VUID-vkCmdBeginQuery-queryType-00805 129 if statistic_flags.is_compute() 130 && !queue_family_properties 131 .queue_flags 132 .intersects(QueueFlags::COMPUTE) 133 || statistic_flags.is_graphics() 134 && !queue_family_properties 135 .queue_flags 136 .intersects(QueueFlags::GRAPHICS) 137 { 138 return Err(QueryError::NotSupportedByQueueFamily); 139 } 140 141 // VUID-vkCmdBeginQuery-queryType-00800 142 if flags.intersects(QueryControlFlags::PRECISE) { 143 return Err(QueryError::InvalidFlags); 144 } 145 } 146 // VUID-vkCmdBeginQuery-queryType-02804 147 QueryType::Timestamp => return Err(QueryError::NotPermitted), 148 } 149 150 // VUID-vkCmdBeginQuery-queryPool-01922 151 if self 152 .query_state 153 .contains_key(&query_pool.query_type().into()) 154 { 155 return Err(QueryError::QueryIsActive); 156 } 157 158 if let Some(render_pass_state) = &self.render_pass_state { 159 // VUID-vkCmdBeginQuery-query-00808 160 if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() { 161 return Err(QueryError::OutOfRangeMultiview); 162 } 163 } 164 165 // VUID-vkCmdBeginQuery-None-00807 166 // Not checked, therefore unsafe. 167 // TODO: add check. 168 169 Ok(()) 170 } 171 172 /// Ends an active query. end_query( &mut self, query_pool: Arc<QueryPool>, query: u32, ) -> Result<&mut Self, QueryError>173 pub fn end_query( 174 &mut self, 175 query_pool: Arc<QueryPool>, 176 query: u32, 177 ) -> Result<&mut Self, QueryError> { 178 self.validate_end_query(&query_pool, query)?; 179 180 unsafe { 181 let raw_ty = query_pool.query_type().into(); 182 self.inner.end_query(query_pool, query); 183 self.query_state.remove(&raw_ty); 184 } 185 186 Ok(self) 187 } 188 validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError>189 fn validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError> { 190 let queue_family_properties = self.queue_family_properties(); 191 192 // VUID-vkCmdEndQuery-commandBuffer-cmdpool 193 if !queue_family_properties 194 .queue_flags 195 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 196 { 197 return Err(QueryError::NotSupportedByQueueFamily); 198 } 199 200 let device = self.device(); 201 202 // VUID-vkCmdEndQuery-commonparent 203 assert_eq!(device, query_pool.device()); 204 205 // VUID-vkCmdEndQuery-None-01923 206 if !self 207 .query_state 208 .get(&query_pool.query_type().into()) 209 .map_or(false, |state| { 210 state.query_pool == query_pool.handle() && state.query == query 211 }) 212 { 213 return Err(QueryError::QueryNotActive); 214 } 215 216 // VUID-vkCmdEndQuery-query-00810 217 query_pool.query(query).ok_or(QueryError::OutOfRange)?; 218 219 if let Some(render_pass_state) = &self.render_pass_state { 220 // VUID-vkCmdEndQuery-query-00812 221 if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() { 222 return Err(QueryError::OutOfRangeMultiview); 223 } 224 } 225 226 Ok(()) 227 } 228 229 /// Writes a timestamp to a timestamp query. 230 /// 231 /// # Safety 232 /// 233 /// The query must be unavailable, ensured by calling 234 /// [`reset_query_pool`](Self::reset_query_pool). write_timestamp( &mut self, query_pool: Arc<QueryPool>, query: u32, stage: PipelineStage, ) -> Result<&mut Self, QueryError>235 pub unsafe fn write_timestamp( 236 &mut self, 237 query_pool: Arc<QueryPool>, 238 query: u32, 239 stage: PipelineStage, 240 ) -> Result<&mut Self, QueryError> { 241 self.validate_write_timestamp(&query_pool, query, stage)?; 242 243 self.inner.write_timestamp(query_pool, query, stage); 244 245 Ok(self) 246 } 247 validate_write_timestamp( &self, query_pool: &QueryPool, query: u32, stage: PipelineStage, ) -> Result<(), QueryError>248 fn validate_write_timestamp( 249 &self, 250 query_pool: &QueryPool, 251 query: u32, 252 stage: PipelineStage, 253 ) -> Result<(), QueryError> { 254 let device = self.device(); 255 256 if !device.enabled_features().synchronization2 && PipelineStages::from(stage).is_2() { 257 return Err(QueryError::RequirementNotMet { 258 required_for: "`stage` has flags set from `VkPipelineStageFlagBits2`", 259 requires_one_of: RequiresOneOf { 260 features: &["synchronization2"], 261 ..Default::default() 262 }, 263 }); 264 } 265 266 // VUID-vkCmdWriteTimestamp2-stage-parameter 267 stage.validate_device(device)?; 268 269 let queue_family_properties = self.queue_family_properties(); 270 271 // VUID-vkCmdWriteTimestamp2-commandBuffer-cmdpool 272 if !queue_family_properties.queue_flags.intersects( 273 QueueFlags::TRANSFER 274 | QueueFlags::GRAPHICS 275 | QueueFlags::COMPUTE 276 | QueueFlags::VIDEO_DECODE 277 | QueueFlags::VIDEO_ENCODE, 278 ) { 279 return Err(QueryError::NotSupportedByQueueFamily); 280 } 281 282 let device = self.device(); 283 284 // VUID-vkCmdWriteTimestamp2-commonparent 285 assert_eq!(device, query_pool.device()); 286 287 // VUID-vkCmdWriteTimestamp2-stage-03860 288 if !PipelineStages::from(queue_family_properties.queue_flags).contains_enum(stage) { 289 return Err(QueryError::StageNotSupported); 290 } 291 292 match stage { 293 PipelineStage::GeometryShader => { 294 // VUID-vkCmdWriteTimestamp2-stage-03929 295 if !device.enabled_features().geometry_shader { 296 return Err(QueryError::RequirementNotMet { 297 required_for: "`stage` is `PipelineStage::GeometryShader`", 298 requires_one_of: RequiresOneOf { 299 features: &["geometry_shadere"], 300 ..Default::default() 301 }, 302 }); 303 } 304 } 305 PipelineStage::TessellationControlShader 306 | PipelineStage::TessellationEvaluationShader => { 307 // VUID-vkCmdWriteTimestamp2-stage-03930 308 if !device.enabled_features().tessellation_shader { 309 return Err(QueryError::RequirementNotMet { 310 required_for: "`stage` is `PipelineStage::TessellationControlShader` or \ 311 `PipelineStage::TessellationEvaluationShader`", 312 requires_one_of: RequiresOneOf { 313 features: &["tessellation_shader"], 314 ..Default::default() 315 }, 316 }); 317 } 318 } 319 PipelineStage::ConditionalRendering => { 320 // VUID-vkCmdWriteTimestamp2-stage-03931 321 if !device.enabled_features().conditional_rendering { 322 return Err(QueryError::RequirementNotMet { 323 required_for: "`stage` is `PipelineStage::ConditionalRendering`", 324 requires_one_of: RequiresOneOf { 325 features: &["conditional_rendering"], 326 ..Default::default() 327 }, 328 }); 329 } 330 } 331 PipelineStage::FragmentDensityProcess => { 332 // VUID-vkCmdWriteTimestamp2-stage-03932 333 if !device.enabled_features().fragment_density_map { 334 return Err(QueryError::RequirementNotMet { 335 required_for: "`stage` is `PipelineStage::FragmentDensityProcess`", 336 requires_one_of: RequiresOneOf { 337 features: &["fragment_density_map"], 338 ..Default::default() 339 }, 340 }); 341 } 342 } 343 PipelineStage::TransformFeedback => { 344 // VUID-vkCmdWriteTimestamp2-stage-03933 345 if !device.enabled_features().transform_feedback { 346 return Err(QueryError::RequirementNotMet { 347 required_for: "`stage` is `PipelineStage::TransformFeedback`", 348 requires_one_of: RequiresOneOf { 349 features: &["transform_feedback"], 350 ..Default::default() 351 }, 352 }); 353 } 354 } 355 PipelineStage::MeshShader => { 356 // VUID-vkCmdWriteTimestamp2-stage-03934 357 if !device.enabled_features().mesh_shader { 358 return Err(QueryError::RequirementNotMet { 359 required_for: "`stage` is `PipelineStage::MeshShader`", 360 requires_one_of: RequiresOneOf { 361 features: &["mesh_shader"], 362 ..Default::default() 363 }, 364 }); 365 } 366 } 367 PipelineStage::TaskShader => { 368 // VUID-vkCmdWriteTimestamp2-stage-03935 369 if !device.enabled_features().task_shader { 370 return Err(QueryError::RequirementNotMet { 371 required_for: "`stage` is `PipelineStage::TaskShader`", 372 requires_one_of: RequiresOneOf { 373 features: &["task_shader"], 374 ..Default::default() 375 }, 376 }); 377 } 378 } 379 PipelineStage::FragmentShadingRateAttachment => { 380 // VUID-vkCmdWriteTimestamp2-shadingRateImage-07316 381 if !(device.enabled_features().attachment_fragment_shading_rate 382 || device.enabled_features().shading_rate_image) 383 { 384 return Err(QueryError::RequirementNotMet { 385 required_for: "`stage` is `PipelineStage::FragmentShadingRateAttachment`", 386 requires_one_of: RequiresOneOf { 387 features: &["attachment_fragment_shading_rate", "shading_rate_image"], 388 ..Default::default() 389 }, 390 }); 391 } 392 } 393 PipelineStage::SubpassShading => { 394 // VUID-vkCmdWriteTimestamp2-stage-04957 395 if !device.enabled_features().subpass_shading { 396 return Err(QueryError::RequirementNotMet { 397 required_for: "`stage` is `PipelineStage::SubpassShading`", 398 requires_one_of: RequiresOneOf { 399 features: &["subpass_shading"], 400 ..Default::default() 401 }, 402 }); 403 } 404 } 405 PipelineStage::InvocationMask => { 406 // VUID-vkCmdWriteTimestamp2-stage-04995 407 if !device.enabled_features().invocation_mask { 408 return Err(QueryError::RequirementNotMet { 409 required_for: "`stage` is `PipelineStage::InvocationMask`", 410 requires_one_of: RequiresOneOf { 411 features: &["invocation_mask"], 412 ..Default::default() 413 }, 414 }); 415 } 416 } 417 _ => (), 418 } 419 420 // VUID-vkCmdWriteTimestamp2-queryPool-03861 421 if !matches!(query_pool.query_type(), QueryType::Timestamp) { 422 return Err(QueryError::NotPermitted); 423 } 424 425 // VUID-vkCmdWriteTimestamp2-timestampValidBits-03863 426 if queue_family_properties.timestamp_valid_bits.is_none() { 427 return Err(QueryError::NoTimestampValidBits); 428 } 429 430 // VUID-vkCmdWriteTimestamp2-query-04903 431 query_pool.query(query).ok_or(QueryError::OutOfRange)?; 432 433 if let Some(render_pass_state) = &self.render_pass_state { 434 // VUID-vkCmdWriteTimestamp2-query-03865 435 if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() { 436 return Err(QueryError::OutOfRangeMultiview); 437 } 438 } 439 440 // VUID-vkCmdWriteTimestamp2-queryPool-03862 441 // VUID-vkCmdWriteTimestamp2-None-03864 442 // Not checked, therefore unsafe. 443 // TODO: add check. 444 445 Ok(()) 446 } 447 448 /// Copies the results of a range of queries to a buffer on the GPU. 449 /// 450 /// [`query_pool.ty().result_len()`] elements will be written for each query in the range, plus 451 /// 1 extra element per query if [`QueryResultFlags::WITH_AVAILABILITY`] is enabled. 452 /// The provided buffer must be large enough to hold the data. 453 /// 454 /// See also [`get_results`]. 455 /// 456 /// [`query_pool.ty().result_len()`]: crate::query::QueryType::result_len 457 /// [`QueryResultFlags::WITH_AVAILABILITY`]: crate::query::QueryResultFlags::WITH_AVAILABILITY 458 /// [`get_results`]: crate::query::QueriesRange::get_results copy_query_pool_results<T>( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, destination: Subbuffer<[T]>, flags: QueryResultFlags, ) -> Result<&mut Self, QueryError> where T: QueryResultElement,459 pub fn copy_query_pool_results<T>( 460 &mut self, 461 query_pool: Arc<QueryPool>, 462 queries: Range<u32>, 463 destination: Subbuffer<[T]>, 464 flags: QueryResultFlags, 465 ) -> Result<&mut Self, QueryError> 466 where 467 T: QueryResultElement, 468 { 469 self.validate_copy_query_pool_results(&query_pool, queries.clone(), &destination, flags)?; 470 471 unsafe { 472 let per_query_len = query_pool.query_type().result_len() 473 + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize; 474 let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize; 475 self.inner 476 .copy_query_pool_results(query_pool, queries, destination, stride, flags)?; 477 } 478 479 Ok(self) 480 } 481 validate_copy_query_pool_results<T>( &self, query_pool: &QueryPool, queries: Range<u32>, destination: &Subbuffer<[T]>, flags: QueryResultFlags, ) -> Result<(), QueryError> where T: QueryResultElement,482 fn validate_copy_query_pool_results<T>( 483 &self, 484 query_pool: &QueryPool, 485 queries: Range<u32>, 486 destination: &Subbuffer<[T]>, 487 flags: QueryResultFlags, 488 ) -> Result<(), QueryError> 489 where 490 T: QueryResultElement, 491 { 492 let queue_family_properties = self.queue_family_properties(); 493 494 // VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool 495 if !queue_family_properties 496 .queue_flags 497 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 498 { 499 return Err(QueryError::NotSupportedByQueueFamily); 500 } 501 502 // VUID-vkCmdCopyQueryPoolResults-renderpass 503 if self.render_pass_state.is_some() { 504 return Err(QueryError::ForbiddenInsideRenderPass); 505 } 506 507 let device = self.device(); 508 509 // VUID-vkCmdCopyQueryPoolResults-commonparent 510 assert_eq!(device, destination.buffer().device()); 511 assert_eq!(device, query_pool.device()); 512 513 assert!(destination.len() > 0); 514 515 // VUID-vkCmdCopyQueryPoolResults-flags-00822 516 // VUID-vkCmdCopyQueryPoolResults-flags-00823 517 debug_assert!(destination.offset() % std::mem::size_of::<T>() as DeviceSize == 0); 518 519 // VUID-vkCmdCopyQueryPoolResults-firstQuery-00820 520 // VUID-vkCmdCopyQueryPoolResults-firstQuery-00821 521 query_pool 522 .queries_range(queries.clone()) 523 .ok_or(QueryError::OutOfRange)?; 524 525 let count = queries.end - queries.start; 526 let per_query_len = query_pool.query_type().result_len() 527 + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize; 528 let required_len = per_query_len * count as DeviceSize; 529 530 // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824 531 if destination.len() < required_len { 532 return Err(QueryError::BufferTooSmall { 533 required_len, 534 actual_len: destination.len(), 535 }); 536 } 537 538 // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825 539 if !destination 540 .buffer() 541 .usage() 542 .intersects(BufferUsage::TRANSFER_DST) 543 { 544 return Err(QueryError::DestinationMissingUsage); 545 } 546 547 // VUID-vkCmdCopyQueryPoolResults-queryType-00827 548 if matches!(query_pool.query_type(), QueryType::Timestamp) 549 && flags.intersects(QueryResultFlags::PARTIAL) 550 { 551 return Err(QueryError::InvalidFlags); 552 } 553 554 Ok(()) 555 } 556 557 /// Resets a range of queries on a query pool. 558 /// 559 /// The affected queries will be marked as "unavailable" after this command runs, and will no 560 /// longer return any results. They will be ready to have new results recorded for them. 561 /// 562 /// # Safety 563 /// The queries in the specified range must not be active in another command buffer. 564 // TODO: Do other command buffers actually matter here? Not sure on the Vulkan spec. reset_query_pool( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, ) -> Result<&mut Self, QueryError>565 pub unsafe fn reset_query_pool( 566 &mut self, 567 query_pool: Arc<QueryPool>, 568 queries: Range<u32>, 569 ) -> Result<&mut Self, QueryError> { 570 self.validate_reset_query_pool(&query_pool, queries.clone())?; 571 572 self.inner.reset_query_pool(query_pool, queries); 573 574 Ok(self) 575 } 576 validate_reset_query_pool( &self, query_pool: &QueryPool, queries: Range<u32>, ) -> Result<(), QueryError>577 fn validate_reset_query_pool( 578 &self, 579 query_pool: &QueryPool, 580 queries: Range<u32>, 581 ) -> Result<(), QueryError> { 582 // VUID-vkCmdResetQueryPool-renderpass 583 if self.render_pass_state.is_some() { 584 return Err(QueryError::ForbiddenInsideRenderPass); 585 } 586 587 let queue_family_properties = self.queue_family_properties(); 588 589 // VUID-vkCmdResetQueryPool-commandBuffer-cmdpool 590 if !queue_family_properties 591 .queue_flags 592 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 593 { 594 return Err(QueryError::NotSupportedByQueueFamily); 595 } 596 597 let device = self.device(); 598 599 // VUID-vkCmdResetQueryPool-commonparent 600 assert_eq!(device, query_pool.device()); 601 602 // VUID-vkCmdResetQueryPool-firstQuery-00796 603 // VUID-vkCmdResetQueryPool-firstQuery-00797 604 query_pool 605 .queries_range(queries.clone()) 606 .ok_or(QueryError::OutOfRange)?; 607 608 // VUID-vkCmdResetQueryPool-None-02841 609 if self 610 .query_state 611 .values() 612 .any(|state| state.query_pool == query_pool.handle() && queries.contains(&state.query)) 613 { 614 return Err(QueryError::QueryIsActive); 615 } 616 617 Ok(()) 618 } 619 } 620 621 impl SyncCommandBufferBuilder { 622 /// Calls `vkCmdBeginQuery` on the builder. 623 #[inline] begin_query( &mut self, query_pool: Arc<QueryPool>, query: u32, flags: QueryControlFlags, )624 pub unsafe fn begin_query( 625 &mut self, 626 query_pool: Arc<QueryPool>, 627 query: u32, 628 flags: QueryControlFlags, 629 ) { 630 struct Cmd { 631 query_pool: Arc<QueryPool>, 632 query: u32, 633 flags: QueryControlFlags, 634 } 635 636 impl Command for Cmd { 637 fn name(&self) -> &'static str { 638 "begin_query" 639 } 640 641 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 642 out.begin_query(self.query_pool.query(self.query).unwrap(), self.flags); 643 } 644 } 645 646 self.commands.push(Box::new(Cmd { 647 query_pool, 648 query, 649 flags, 650 })); 651 } 652 653 /// Calls `vkCmdEndQuery` on the builder. 654 #[inline] end_query(&mut self, query_pool: Arc<QueryPool>, query: u32)655 pub unsafe fn end_query(&mut self, query_pool: Arc<QueryPool>, query: u32) { 656 struct Cmd { 657 query_pool: Arc<QueryPool>, 658 query: u32, 659 } 660 661 impl Command for Cmd { 662 fn name(&self) -> &'static str { 663 "end_query" 664 } 665 666 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 667 out.end_query(self.query_pool.query(self.query).unwrap()); 668 } 669 } 670 671 self.commands.push(Box::new(Cmd { query_pool, query })); 672 } 673 674 /// Calls `vkCmdWriteTimestamp` on the builder. 675 #[inline] write_timestamp( &mut self, query_pool: Arc<QueryPool>, query: u32, stage: PipelineStage, )676 pub unsafe fn write_timestamp( 677 &mut self, 678 query_pool: Arc<QueryPool>, 679 query: u32, 680 stage: PipelineStage, 681 ) { 682 struct Cmd { 683 query_pool: Arc<QueryPool>, 684 query: u32, 685 stage: PipelineStage, 686 } 687 688 impl Command for Cmd { 689 fn name(&self) -> &'static str { 690 "write_timestamp" 691 } 692 693 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 694 out.write_timestamp(self.query_pool.query(self.query).unwrap(), self.stage); 695 } 696 } 697 698 self.commands.push(Box::new(Cmd { 699 query_pool, 700 query, 701 stage, 702 })); 703 } 704 705 /// Calls `vkCmdCopyQueryPoolResults` on the builder. 706 /// 707 /// # Safety 708 /// `stride` must be at least the number of bytes that will be written by each query. copy_query_pool_results( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, destination: Subbuffer<[impl QueryResultElement]>, stride: DeviceSize, flags: QueryResultFlags, ) -> Result<(), SyncCommandBufferBuilderError>709 pub unsafe fn copy_query_pool_results( 710 &mut self, 711 query_pool: Arc<QueryPool>, 712 queries: Range<u32>, 713 destination: Subbuffer<[impl QueryResultElement]>, 714 stride: DeviceSize, 715 flags: QueryResultFlags, 716 ) -> Result<(), SyncCommandBufferBuilderError> { 717 struct Cmd<T> { 718 query_pool: Arc<QueryPool>, 719 queries: Range<u32>, 720 destination: Subbuffer<[T]>, 721 stride: DeviceSize, 722 flags: QueryResultFlags, 723 } 724 725 impl<T> Command for Cmd<T> 726 where 727 T: QueryResultElement, 728 { 729 fn name(&self) -> &'static str { 730 "copy_query_pool_results" 731 } 732 733 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 734 out.copy_query_pool_results( 735 self.query_pool.queries_range(self.queries.clone()).unwrap(), 736 &self.destination, 737 self.stride, 738 self.flags, 739 ); 740 } 741 } 742 743 let command_index = self.commands.len(); 744 let command_name = "copy_query_pool_results"; 745 let resources = [( 746 ResourceUseRef { 747 command_index, 748 command_name, 749 resource_in_command: ResourceInCommand::Destination, 750 secondary_use_ref: None, 751 }, 752 Resource::Buffer { 753 buffer: destination.as_bytes().clone(), 754 range: 0..destination.size(), // TODO: 755 memory: PipelineMemoryAccess { 756 stages: PipelineStages::ALL_TRANSFER, 757 access: AccessFlags::TRANSFER_WRITE, 758 exclusive: true, 759 }, 760 }, 761 )]; 762 763 for resource in &resources { 764 self.check_resource_conflicts(resource)?; 765 } 766 767 self.commands.push(Box::new(Cmd { 768 query_pool, 769 queries, 770 destination, 771 stride, 772 flags, 773 })); 774 775 for resource in resources { 776 self.add_resource(resource); 777 } 778 779 Ok(()) 780 } 781 782 /// Calls `vkCmdResetQueryPool` on the builder. 783 #[inline] reset_query_pool(&mut self, query_pool: Arc<QueryPool>, queries: Range<u32>)784 pub unsafe fn reset_query_pool(&mut self, query_pool: Arc<QueryPool>, queries: Range<u32>) { 785 struct Cmd { 786 query_pool: Arc<QueryPool>, 787 queries: Range<u32>, 788 } 789 790 impl Command for Cmd { 791 fn name(&self) -> &'static str { 792 "reset_query_pool" 793 } 794 795 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 796 out.reset_query_pool(self.query_pool.queries_range(self.queries.clone()).unwrap()); 797 } 798 } 799 800 self.commands.push(Box::new(Cmd { 801 query_pool, 802 queries, 803 })); 804 } 805 } 806 807 impl UnsafeCommandBufferBuilder { 808 /// Calls `vkCmdBeginQuery` on the builder. 809 #[inline] begin_query(&mut self, query: Query<'_>, flags: QueryControlFlags)810 pub unsafe fn begin_query(&mut self, query: Query<'_>, flags: QueryControlFlags) { 811 let fns = self.device.fns(); 812 (fns.v1_0.cmd_begin_query)( 813 self.handle, 814 query.pool().handle(), 815 query.index(), 816 flags.into(), 817 ); 818 } 819 820 /// Calls `vkCmdEndQuery` on the builder. 821 #[inline] end_query(&mut self, query: Query<'_>)822 pub unsafe fn end_query(&mut self, query: Query<'_>) { 823 let fns = self.device.fns(); 824 (fns.v1_0.cmd_end_query)(self.handle, query.pool().handle(), query.index()); 825 } 826 827 /// Calls `vkCmdWriteTimestamp` on the builder. 828 #[inline] write_timestamp(&mut self, query: Query<'_>, stage: PipelineStage)829 pub unsafe fn write_timestamp(&mut self, query: Query<'_>, stage: PipelineStage) { 830 let fns = self.device.fns(); 831 832 if self.device.enabled_features().synchronization2 { 833 if self.device.api_version() >= Version::V1_3 { 834 (fns.v1_3.cmd_write_timestamp2)( 835 self.handle, 836 stage.into(), 837 query.pool().handle(), 838 query.index(), 839 ); 840 } else { 841 debug_assert!(self.device.enabled_extensions().khr_synchronization2); 842 (fns.khr_synchronization2.cmd_write_timestamp2_khr)( 843 self.handle, 844 stage.into(), 845 query.pool().handle(), 846 query.index(), 847 ); 848 } 849 } else { 850 (fns.v1_0.cmd_write_timestamp)( 851 self.handle, 852 stage.into(), 853 query.pool().handle(), 854 query.index(), 855 ); 856 } 857 } 858 859 /// Calls `vkCmdCopyQueryPoolResults` on the builder. copy_query_pool_results<T>( &mut self, queries: QueriesRange<'_>, destination: &Subbuffer<[T]>, stride: DeviceSize, flags: QueryResultFlags, ) where T: QueryResultElement,860 pub unsafe fn copy_query_pool_results<T>( 861 &mut self, 862 queries: QueriesRange<'_>, 863 destination: &Subbuffer<[T]>, 864 stride: DeviceSize, 865 flags: QueryResultFlags, 866 ) where 867 T: QueryResultElement, 868 { 869 let range = queries.range(); 870 debug_assert!(destination.offset() < destination.buffer().size()); 871 debug_assert!(destination 872 .buffer() 873 .usage() 874 .intersects(BufferUsage::TRANSFER_DST)); 875 debug_assert!(destination.offset() % size_of::<T>() as DeviceSize == 0); 876 debug_assert!(stride % size_of::<T>() as DeviceSize == 0); 877 878 let fns = self.device.fns(); 879 (fns.v1_0.cmd_copy_query_pool_results)( 880 self.handle, 881 queries.pool().handle(), 882 range.start, 883 range.end - range.start, 884 destination.buffer().handle(), 885 destination.offset(), 886 stride, 887 ash::vk::QueryResultFlags::from(flags) | T::FLAG, 888 ); 889 } 890 891 /// Calls `vkCmdResetQueryPool` on the builder. 892 #[inline] reset_query_pool(&mut self, queries: QueriesRange<'_>)893 pub unsafe fn reset_query_pool(&mut self, queries: QueriesRange<'_>) { 894 let range = queries.range(); 895 let fns = self.device.fns(); 896 (fns.v1_0.cmd_reset_query_pool)( 897 self.handle, 898 queries.pool().handle(), 899 range.start, 900 range.end - range.start, 901 ); 902 } 903 } 904 905 /// Error that can happen when recording a query command. 906 #[derive(Clone, Debug)] 907 pub enum QueryError { 908 SyncCommandBufferBuilderError(SyncCommandBufferBuilderError), 909 910 RequirementNotMet { 911 required_for: &'static str, 912 requires_one_of: RequiresOneOf, 913 }, 914 915 /// The buffer is too small for the copy operation. 916 BufferTooSmall { 917 /// Required number of elements in the buffer. 918 required_len: DeviceSize, 919 /// Actual number of elements in the buffer. 920 actual_len: DeviceSize, 921 }, 922 923 /// The destination buffer is missing the `transfer_dst` usage. 924 DestinationMissingUsage, 925 926 /// Operation forbidden inside of a render pass. 927 ForbiddenInsideRenderPass, 928 929 /// The provided flags are not allowed for this type of query. 930 InvalidFlags, 931 932 /// The queue family's `timestamp_valid_bits` value is `None`. 933 NoTimestampValidBits, 934 935 /// This operation is not permitted on this query type. 936 NotPermitted, 937 938 /// The queue family doesn't allow this operation. 939 NotSupportedByQueueFamily, 940 941 /// The provided query index is not valid for this pool. 942 OutOfRange, 943 944 /// The provided query index plus the number of views in the current render subpass is greater 945 /// than the number of queries in the pool. 946 OutOfRangeMultiview, 947 948 /// A query is active that conflicts with the current operation. 949 QueryIsActive, 950 951 /// This query was not active. 952 QueryNotActive, 953 954 /// The provided stage is not supported by the queue family. 955 StageNotSupported, 956 } 957 958 impl Error for QueryError {} 959 960 impl Display for QueryError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>961 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 962 match self { 963 Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"), 964 Self::RequirementNotMet { 965 required_for, 966 requires_one_of, 967 } => write!( 968 f, 969 "a requirement was not met for: {}; requires one of: {}", 970 required_for, requires_one_of, 971 ), 972 Self::BufferTooSmall { .. } => { 973 write!(f, "the buffer is too small for the copy operation") 974 } 975 Self::DestinationMissingUsage => write!( 976 f, 977 "the destination buffer is missing the `transfer_dst` usage", 978 ), 979 Self::ForbiddenInsideRenderPass => { 980 write!(f, "operation forbidden inside of a render pass") 981 } 982 Self::InvalidFlags => write!( 983 f, 984 "the provided flags are not allowed for this type of query", 985 ), 986 Self::NoTimestampValidBits => { 987 write!(f, "the queue family's timestamp_valid_bits value is None") 988 } 989 Self::NotPermitted => write!(f, "this operation is not permitted on this query type"), 990 Self::NotSupportedByQueueFamily => { 991 write!(f, "the queue family doesn't allow this operation") 992 } 993 Self::OutOfRange => write!(f, "the provided query index is not valid for this pool"), 994 Self::OutOfRangeMultiview => write!( 995 f, 996 "the provided query index plus the number of views in the current render subpass \ 997 is greater than the number of queries in the pool", 998 ), 999 Self::QueryIsActive => write!( 1000 f, 1001 "a query is active that conflicts with the current operation" 1002 ), 1003 Self::QueryNotActive => write!(f, "this query was not active"), 1004 Self::StageNotSupported => { 1005 write!(f, "the provided stage is not supported by the queue family") 1006 } 1007 } 1008 } 1009 } 1010 1011 impl From<SyncCommandBufferBuilderError> for QueryError { from(err: SyncCommandBufferBuilderError) -> Self1012 fn from(err: SyncCommandBufferBuilderError) -> Self { 1013 Self::SyncCommandBufferBuilderError(err) 1014 } 1015 } 1016 1017 impl From<RequirementNotMet> for QueryError { from(err: RequirementNotMet) -> Self1018 fn from(err: RequirementNotMet) -> Self { 1019 Self::RequirementNotMet { 1020 required_for: err.required_for, 1021 requires_one_of: err.requires_one_of, 1022 } 1023 } 1024 } 1025