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 super::{CommandBufferBuilder, QueryError, QueryState}; 11 use crate::{ 12 buffer::{BufferUsage, Subbuffer}, 13 command_buffer::{allocator::CommandBufferAllocator, ResourceInCommand, ResourceUseRef}, 14 device::{DeviceOwned, QueueFlags}, 15 query::{QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags, QueryType}, 16 sync::{PipelineStage, PipelineStageAccess, PipelineStages}, 17 DeviceSize, RequiresOneOf, Version, VulkanObject, 18 }; 19 use std::{ops::Range, sync::Arc}; 20 21 impl<L, A> CommandBufferBuilder<L, A> 22 where 23 A: CommandBufferAllocator, 24 { 25 /// Begins a query. 26 /// 27 /// The query will be active until [`end_query`] is called for the same query. 28 /// 29 /// # Safety 30 /// 31 /// - The query must be unavailable, ensured by calling [`reset_query_pool`]. 32 /// 33 /// [`end_query`]: Self::end_query 34 /// [`reset_query_pool`]: Self::reset_query_pool 35 #[inline] begin_query( &mut self, query_pool: Arc<QueryPool>, query: u32, flags: QueryControlFlags, ) -> Result<&mut Self, QueryError>36 pub unsafe fn begin_query( 37 &mut self, 38 query_pool: Arc<QueryPool>, 39 query: u32, 40 flags: QueryControlFlags, 41 ) -> Result<&mut Self, QueryError> { 42 self.validate_begin_query(&query_pool, query, flags)?; 43 44 Ok(self.begin_query_unchecked(query_pool, query, flags)) 45 } 46 validate_begin_query( &self, query_pool: &QueryPool, query: u32, flags: QueryControlFlags, ) -> Result<(), QueryError>47 fn validate_begin_query( 48 &self, 49 query_pool: &QueryPool, 50 query: u32, 51 flags: QueryControlFlags, 52 ) -> Result<(), QueryError> { 53 let queue_family_properties = self.queue_family_properties(); 54 55 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 56 if !queue_family_properties 57 .queue_flags 58 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 59 { 60 return Err(QueryError::NotSupportedByQueueFamily); 61 } 62 63 let device = self.device(); 64 65 // VUID-vkCmdBeginQuery-flags-parameter 66 flags.validate_device(device)?; 67 68 // VUID-vkCmdBeginQuery-commonparent 69 assert_eq!(device, query_pool.device()); 70 71 // VUID-vkCmdBeginQuery-query-00802 72 query_pool.query(query).ok_or(QueryError::OutOfRange)?; 73 74 match query_pool.query_type() { 75 QueryType::Occlusion => { 76 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 77 // // VUID-vkCmdBeginQuery-queryType-00803 78 if !queue_family_properties 79 .queue_flags 80 .intersects(QueueFlags::GRAPHICS) 81 { 82 return Err(QueryError::NotSupportedByQueueFamily); 83 } 84 85 // VUID-vkCmdBeginQuery-queryType-00800 86 if flags.intersects(QueryControlFlags::PRECISE) 87 && !device.enabled_features().occlusion_query_precise 88 { 89 return Err(QueryError::RequirementNotMet { 90 required_for: "`flags` contains `QueryControlFlags::PRECISE`", 91 requires_one_of: RequiresOneOf { 92 features: &["occlusion_query_precise"], 93 ..Default::default() 94 }, 95 }); 96 } 97 } 98 QueryType::PipelineStatistics(statistic_flags) => { 99 // VUID-vkCmdBeginQuery-commandBuffer-cmdpool 100 // VUID-vkCmdBeginQuery-queryType-00804 101 // VUID-vkCmdBeginQuery-queryType-00805 102 if statistic_flags.is_compute() 103 && !queue_family_properties 104 .queue_flags 105 .intersects(QueueFlags::COMPUTE) 106 || statistic_flags.is_graphics() 107 && !queue_family_properties 108 .queue_flags 109 .intersects(QueueFlags::GRAPHICS) 110 { 111 return Err(QueryError::NotSupportedByQueueFamily); 112 } 113 114 // VUID-vkCmdBeginQuery-queryType-00800 115 if flags.intersects(QueryControlFlags::PRECISE) { 116 return Err(QueryError::InvalidFlags); 117 } 118 } 119 // VUID-vkCmdBeginQuery-queryType-02804 120 QueryType::Timestamp => return Err(QueryError::NotPermitted), 121 } 122 123 // VUID-vkCmdBeginQuery-queryPool-01922 124 if self 125 .builder_state 126 .queries 127 .contains_key(&query_pool.query_type().into()) 128 { 129 return Err(QueryError::QueryIsActive); 130 } 131 132 if let Some(render_pass_state) = &self.builder_state.render_pass { 133 // VUID-vkCmdBeginQuery-query-00808 134 if query + render_pass_state.rendering_info.view_mask.count_ones() 135 > query_pool.query_count() 136 { 137 return Err(QueryError::OutOfRangeMultiview); 138 } 139 } 140 141 // VUID-vkCmdBeginQuery-None-00807 142 // Not checked, therefore unsafe. 143 // TODO: add check. 144 145 Ok(()) 146 } 147 148 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] begin_query_unchecked( &mut self, query_pool: Arc<QueryPool>, query: u32, flags: QueryControlFlags, ) -> &mut Self149 pub unsafe fn begin_query_unchecked( 150 &mut self, 151 query_pool: Arc<QueryPool>, 152 query: u32, 153 flags: QueryControlFlags, 154 ) -> &mut Self { 155 let fns = self.device().fns(); 156 (fns.v1_0.cmd_begin_query)(self.handle(), query_pool.handle(), query, flags.into()); 157 158 let ty = query_pool.query_type(); 159 self.builder_state.queries.insert( 160 ty.into(), 161 QueryState { 162 query_pool: query_pool.handle(), 163 query, 164 ty, 165 flags, 166 in_subpass: self.builder_state.render_pass.is_some(), 167 }, 168 ); 169 170 self.resources.push(Box::new(query_pool)); 171 172 self.next_command_index += 1; 173 self 174 } 175 176 /// Ends an active query. 177 #[inline] end_query( &mut self, query_pool: Arc<QueryPool>, query: u32, ) -> Result<&mut Self, QueryError>178 pub fn end_query( 179 &mut self, 180 query_pool: Arc<QueryPool>, 181 query: u32, 182 ) -> Result<&mut Self, QueryError> { 183 self.validate_end_query(&query_pool, query)?; 184 185 unsafe { Ok(self.end_query_unchecked(query_pool, query)) } 186 } 187 validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError>188 fn validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError> { 189 let queue_family_properties = self.queue_family_properties(); 190 191 // VUID-vkCmdEndQuery-commandBuffer-cmdpool 192 if !queue_family_properties 193 .queue_flags 194 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 195 { 196 return Err(QueryError::NotSupportedByQueueFamily); 197 } 198 199 let device = self.device(); 200 201 // VUID-vkCmdEndQuery-commonparent 202 assert_eq!(device, query_pool.device()); 203 204 // VUID-vkCmdEndQuery-None-01923 205 if !self 206 .builder_state 207 .queries 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.builder_state.render_pass { 220 // VUID-vkCmdEndQuery-query-00812 221 if query + render_pass_state.rendering_info.view_mask.count_ones() 222 > query_pool.query_count() 223 { 224 return Err(QueryError::OutOfRangeMultiview); 225 } 226 } 227 228 Ok(()) 229 } 230 231 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] end_query_unchecked( &mut self, query_pool: Arc<QueryPool>, query: u32, ) -> &mut Self232 pub unsafe fn end_query_unchecked( 233 &mut self, 234 query_pool: Arc<QueryPool>, 235 query: u32, 236 ) -> &mut Self { 237 let fns = self.device().fns(); 238 (fns.v1_0.cmd_end_query)(self.handle(), query_pool.handle(), query); 239 240 self.builder_state 241 .queries 242 .remove(&query_pool.query_type().into()); 243 244 self.resources.push(Box::new(query_pool)); 245 246 self.next_command_index += 1; 247 self 248 } 249 250 /// Writes a timestamp to a timestamp query. 251 /// 252 /// # Safety 253 /// 254 /// - The query must be unavailable, ensured by calling [`reset_query_pool`]. 255 /// 256 /// [`reset_query_pool`]: Self::reset_query_pool write_timestamp( &mut self, query_pool: Arc<QueryPool>, query: u32, stage: PipelineStage, ) -> Result<&mut Self, QueryError>257 pub unsafe fn write_timestamp( 258 &mut self, 259 query_pool: Arc<QueryPool>, 260 query: u32, 261 stage: PipelineStage, 262 ) -> Result<&mut Self, QueryError> { 263 self.validate_write_timestamp(&query_pool, query, stage)?; 264 265 Ok(self.write_timestamp_unchecked(query_pool, query, stage)) 266 } 267 validate_write_timestamp( &self, query_pool: &QueryPool, query: u32, stage: PipelineStage, ) -> Result<(), QueryError>268 fn validate_write_timestamp( 269 &self, 270 query_pool: &QueryPool, 271 query: u32, 272 stage: PipelineStage, 273 ) -> Result<(), QueryError> { 274 let device = self.device(); 275 276 if !device.enabled_features().synchronization2 && PipelineStages::from(stage).is_2() { 277 return Err(QueryError::RequirementNotMet { 278 required_for: "`stage` has flags set from `VkPipelineStageFlagBits2`", 279 requires_one_of: RequiresOneOf { 280 features: &["synchronization2"], 281 ..Default::default() 282 }, 283 }); 284 } 285 286 // VUID-vkCmdWriteTimestamp2-stage-parameter 287 stage.validate_device(device)?; 288 289 let queue_family_properties = self.queue_family_properties(); 290 291 // VUID-vkCmdWriteTimestamp2-commandBuffer-cmdpool 292 if !queue_family_properties.queue_flags.intersects( 293 QueueFlags::TRANSFER 294 | QueueFlags::GRAPHICS 295 | QueueFlags::COMPUTE 296 | QueueFlags::VIDEO_DECODE 297 | QueueFlags::VIDEO_ENCODE, 298 ) { 299 return Err(QueryError::NotSupportedByQueueFamily); 300 } 301 302 let device = self.device(); 303 304 // VUID-vkCmdWriteTimestamp2-commonparent 305 assert_eq!(device, query_pool.device()); 306 307 // VUID-vkCmdWriteTimestamp2-stage-03860 308 if !PipelineStages::from(queue_family_properties.queue_flags).contains_enum(stage) { 309 return Err(QueryError::StageNotSupported); 310 } 311 312 match stage { 313 PipelineStage::GeometryShader => { 314 // VUID-vkCmdWriteTimestamp2-stage-03929 315 if !device.enabled_features().geometry_shader { 316 return Err(QueryError::RequirementNotMet { 317 required_for: "`stage` is `PipelineStage::GeometryShader`", 318 requires_one_of: RequiresOneOf { 319 features: &["geometry_shadere"], 320 ..Default::default() 321 }, 322 }); 323 } 324 } 325 PipelineStage::TessellationControlShader 326 | PipelineStage::TessellationEvaluationShader => { 327 // VUID-vkCmdWriteTimestamp2-stage-03930 328 if !device.enabled_features().tessellation_shader { 329 return Err(QueryError::RequirementNotMet { 330 required_for: "`stage` is `PipelineStage::TessellationControlShader` or \ 331 `PipelineStage::TessellationEvaluationShader`", 332 requires_one_of: RequiresOneOf { 333 features: &["tessellation_shader"], 334 ..Default::default() 335 }, 336 }); 337 } 338 } 339 PipelineStage::ConditionalRendering => { 340 // VUID-vkCmdWriteTimestamp2-stage-03931 341 if !device.enabled_features().conditional_rendering { 342 return Err(QueryError::RequirementNotMet { 343 required_for: "`stage` is `PipelineStage::ConditionalRendering`", 344 requires_one_of: RequiresOneOf { 345 features: &["conditional_rendering"], 346 ..Default::default() 347 }, 348 }); 349 } 350 } 351 PipelineStage::FragmentDensityProcess => { 352 // VUID-vkCmdWriteTimestamp2-stage-03932 353 if !device.enabled_features().fragment_density_map { 354 return Err(QueryError::RequirementNotMet { 355 required_for: "`stage` is `PipelineStage::FragmentDensityProcess`", 356 requires_one_of: RequiresOneOf { 357 features: &["fragment_density_map"], 358 ..Default::default() 359 }, 360 }); 361 } 362 } 363 PipelineStage::TransformFeedback => { 364 // VUID-vkCmdWriteTimestamp2-stage-03933 365 if !device.enabled_features().transform_feedback { 366 return Err(QueryError::RequirementNotMet { 367 required_for: "`stage` is `PipelineStage::TransformFeedback`", 368 requires_one_of: RequiresOneOf { 369 features: &["transform_feedback"], 370 ..Default::default() 371 }, 372 }); 373 } 374 } 375 PipelineStage::MeshShader => { 376 // VUID-vkCmdWriteTimestamp2-stage-03934 377 if !device.enabled_features().mesh_shader { 378 return Err(QueryError::RequirementNotMet { 379 required_for: "`stage` is `PipelineStage::MeshShader`", 380 requires_one_of: RequiresOneOf { 381 features: &["mesh_shader"], 382 ..Default::default() 383 }, 384 }); 385 } 386 } 387 PipelineStage::TaskShader => { 388 // VUID-vkCmdWriteTimestamp2-stage-03935 389 if !device.enabled_features().task_shader { 390 return Err(QueryError::RequirementNotMet { 391 required_for: "`stage` is `PipelineStage::TaskShader`", 392 requires_one_of: RequiresOneOf { 393 features: &["task_shader"], 394 ..Default::default() 395 }, 396 }); 397 } 398 } 399 PipelineStage::FragmentShadingRateAttachment => { 400 // VUID-vkCmdWriteTimestamp2-shadingRateImage-07316 401 if !(device.enabled_features().attachment_fragment_shading_rate 402 || device.enabled_features().shading_rate_image) 403 { 404 return Err(QueryError::RequirementNotMet { 405 required_for: "`stage` is `PipelineStage::FragmentShadingRateAttachment`", 406 requires_one_of: RequiresOneOf { 407 features: &["attachment_fragment_shading_rate", "shading_rate_image"], 408 ..Default::default() 409 }, 410 }); 411 } 412 } 413 PipelineStage::SubpassShading => { 414 // VUID-vkCmdWriteTimestamp2-stage-04957 415 if !device.enabled_features().subpass_shading { 416 return Err(QueryError::RequirementNotMet { 417 required_for: "`stage` is `PipelineStage::SubpassShading`", 418 requires_one_of: RequiresOneOf { 419 features: &["subpass_shading"], 420 ..Default::default() 421 }, 422 }); 423 } 424 } 425 PipelineStage::InvocationMask => { 426 // VUID-vkCmdWriteTimestamp2-stage-04995 427 if !device.enabled_features().invocation_mask { 428 return Err(QueryError::RequirementNotMet { 429 required_for: "`stage` is `PipelineStage::InvocationMask`", 430 requires_one_of: RequiresOneOf { 431 features: &["invocation_mask"], 432 ..Default::default() 433 }, 434 }); 435 } 436 } 437 _ => (), 438 } 439 440 // VUID-vkCmdWriteTimestamp2-queryPool-03861 441 if !matches!(query_pool.query_type(), QueryType::Timestamp) { 442 return Err(QueryError::NotPermitted); 443 } 444 445 // VUID-vkCmdWriteTimestamp2-timestampValidBits-03863 446 if queue_family_properties.timestamp_valid_bits.is_none() { 447 return Err(QueryError::NoTimestampValidBits); 448 } 449 450 // VUID-vkCmdWriteTimestamp2-query-04903 451 query_pool.query(query).ok_or(QueryError::OutOfRange)?; 452 453 if let Some(render_pass_state) = &self.builder_state.render_pass { 454 // VUID-vkCmdWriteTimestamp2-query-03865 455 if query + render_pass_state.rendering_info.view_mask.count_ones() 456 > query_pool.query_count() 457 { 458 return Err(QueryError::OutOfRangeMultiview); 459 } 460 } 461 462 // VUID-vkCmdWriteTimestamp2-queryPool-03862 463 // VUID-vkCmdWriteTimestamp2-None-03864 464 // Not checked, therefore unsafe. 465 // TODO: add check. 466 467 Ok(()) 468 } 469 470 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] write_timestamp_unchecked( &mut self, query_pool: Arc<QueryPool>, query: u32, stage: PipelineStage, ) -> &mut Self471 pub unsafe fn write_timestamp_unchecked( 472 &mut self, 473 query_pool: Arc<QueryPool>, 474 query: u32, 475 stage: PipelineStage, 476 ) -> &mut Self { 477 let fns = self.device().fns(); 478 479 if self.device().enabled_features().synchronization2 { 480 if self.device().api_version() >= Version::V1_3 { 481 (fns.v1_3.cmd_write_timestamp2)( 482 self.handle(), 483 stage.into(), 484 query_pool.handle(), 485 query, 486 ); 487 } else { 488 debug_assert!(self.device().enabled_extensions().khr_synchronization2); 489 (fns.khr_synchronization2.cmd_write_timestamp2_khr)( 490 self.handle(), 491 stage.into(), 492 query_pool.handle(), 493 query, 494 ); 495 } 496 } else { 497 (fns.v1_0.cmd_write_timestamp)(self.handle(), stage.into(), query_pool.handle(), query); 498 } 499 500 self.resources.push(Box::new(query_pool)); 501 502 self.next_command_index += 1; 503 self 504 } 505 506 /// Copies the results of a range of queries to a buffer on the GPU. 507 /// 508 /// [`query_pool.ty().result_len()`] elements will be written for each query in the range, plus 509 /// 1 extra element per query if [`QueryResultFlags::WITH_AVAILABILITY`] is enabled. 510 /// The provided buffer must be large enough to hold the data. 511 /// 512 /// See also [`get_results`]. 513 /// 514 /// # Safety 515 /// 516 /// - Appropriate synchronization must be provided for all buffers 517 /// that are accessed by the command. 518 /// 519 /// [`query_pool.ty().result_len()`]: crate::query::QueryType::result_len 520 /// [`QueryResultFlags::WITH_AVAILABILITY`]: crate::query::QueryResultFlags::WITH_AVAILABILITY 521 /// [`get_results`]: crate::query::QueriesRange::get_results copy_query_pool_results<T>( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, dst_buffer: Subbuffer<[T]>, flags: QueryResultFlags, ) -> Result<&mut Self, QueryError> where T: QueryResultElement,522 pub unsafe fn copy_query_pool_results<T>( 523 &mut self, 524 query_pool: Arc<QueryPool>, 525 queries: Range<u32>, 526 dst_buffer: Subbuffer<[T]>, 527 flags: QueryResultFlags, 528 ) -> Result<&mut Self, QueryError> 529 where 530 T: QueryResultElement, 531 { 532 self.validate_copy_query_pool_results( 533 &query_pool, 534 queries.clone(), 535 dst_buffer.as_bytes(), 536 std::mem::size_of::<T>() as DeviceSize, 537 flags, 538 )?; 539 540 unsafe { 541 let per_query_len = query_pool.query_type().result_len() 542 + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize; 543 let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize; 544 Ok(self 545 .copy_query_pool_results_unchecked(query_pool, queries, dst_buffer, stride, flags)) 546 } 547 } 548 validate_copy_query_pool_results( &self, query_pool: &QueryPool, queries: Range<u32>, dst_buffer: &Subbuffer<[u8]>, element_size: DeviceSize, flags: QueryResultFlags, ) -> Result<(), QueryError>549 fn validate_copy_query_pool_results( 550 &self, 551 query_pool: &QueryPool, 552 queries: Range<u32>, 553 dst_buffer: &Subbuffer<[u8]>, 554 element_size: DeviceSize, 555 flags: QueryResultFlags, 556 ) -> Result<(), QueryError> { 557 let queue_family_properties = self.queue_family_properties(); 558 559 // VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool 560 if !queue_family_properties 561 .queue_flags 562 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 563 { 564 return Err(QueryError::NotSupportedByQueueFamily); 565 } 566 567 // VUID-vkCmdCopyQueryPoolResults-renderpass 568 if self.builder_state.render_pass.is_some() { 569 return Err(QueryError::ForbiddenInsideRenderPass); 570 } 571 572 let device = self.device(); 573 574 // VUID-vkCmdCopyQueryPoolResults-commonparent 575 assert_eq!(device, dst_buffer.buffer().device()); 576 assert_eq!(device, query_pool.device()); 577 578 assert!(dst_buffer.len() > 0); 579 580 // VUID-vkCmdCopyQueryPoolResults-flags-00822 581 // VUID-vkCmdCopyQueryPoolResults-flags-00823 582 debug_assert!(dst_buffer.offset() % element_size == 0); 583 584 // VUID-vkCmdCopyQueryPoolResults-firstQuery-00820 585 // VUID-vkCmdCopyQueryPoolResults-firstQuery-00821 586 query_pool 587 .queries_range(queries.clone()) 588 .ok_or(QueryError::OutOfRange)?; 589 590 let count = queries.end - queries.start; 591 let per_query_len = query_pool.query_type().result_len() 592 + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize; 593 let required_len = per_query_len * count as DeviceSize; 594 595 // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824 596 if dst_buffer.len() < required_len { 597 return Err(QueryError::BufferTooSmall { 598 required_len, 599 actual_len: dst_buffer.len(), 600 }); 601 } 602 603 // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825 604 if !dst_buffer 605 .buffer() 606 .usage() 607 .intersects(BufferUsage::TRANSFER_DST) 608 { 609 return Err(QueryError::DestinationMissingUsage); 610 } 611 612 // VUID-vkCmdCopyQueryPoolResults-queryType-00827 613 if matches!(query_pool.query_type(), QueryType::Timestamp) 614 && flags.intersects(QueryResultFlags::PARTIAL) 615 { 616 return Err(QueryError::InvalidFlags); 617 } 618 619 // TODO: sync check 620 621 Ok(()) 622 } 623 624 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] copy_query_pool_results_unchecked<T>( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, dst_buffer: Subbuffer<[T]>, stride: DeviceSize, flags: QueryResultFlags, ) -> &mut Self where T: QueryResultElement,625 pub unsafe fn copy_query_pool_results_unchecked<T>( 626 &mut self, 627 query_pool: Arc<QueryPool>, 628 queries: Range<u32>, 629 dst_buffer: Subbuffer<[T]>, 630 stride: DeviceSize, 631 flags: QueryResultFlags, 632 ) -> &mut Self 633 where 634 T: QueryResultElement, 635 { 636 let fns = self.device().fns(); 637 (fns.v1_0.cmd_copy_query_pool_results)( 638 self.handle(), 639 query_pool.handle(), 640 queries.start, 641 queries.end - queries.start, 642 dst_buffer.buffer().handle(), 643 dst_buffer.offset(), 644 stride, 645 ash::vk::QueryResultFlags::from(flags) | T::FLAG, 646 ); 647 648 let command_index = self.next_command_index; 649 let command_name = "copy_query_pool_results"; 650 let use_ref = ResourceUseRef { 651 command_index, 652 command_name, 653 resource_in_command: ResourceInCommand::Destination, 654 secondary_use_ref: None, 655 }; 656 657 self.resources_usage_state.record_buffer_access( 658 &use_ref, 659 dst_buffer.buffer(), 660 dst_buffer.range(), 661 PipelineStageAccess::Copy_TransferWrite, 662 ); 663 664 self.resources.push(Box::new(query_pool)); 665 self.resources.push(Box::new(dst_buffer)); 666 667 self.next_command_index += 1; 668 self 669 } 670 671 /// Resets a range of queries on a query pool. 672 /// 673 /// The affected queries will be marked as "unavailable" after this command runs, and will no 674 /// longer return any results. They will be ready to have new results recorded for them. 675 /// 676 /// # Safety 677 /// The queries in the specified range must not be active in another command buffer. 678 // 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>679 pub unsafe fn reset_query_pool( 680 &mut self, 681 query_pool: Arc<QueryPool>, 682 queries: Range<u32>, 683 ) -> Result<&mut Self, QueryError> { 684 self.validate_reset_query_pool(&query_pool, queries.clone())?; 685 686 Ok(self.reset_query_pool_unchecked(query_pool, queries)) 687 } 688 validate_reset_query_pool( &self, query_pool: &QueryPool, queries: Range<u32>, ) -> Result<(), QueryError>689 fn validate_reset_query_pool( 690 &self, 691 query_pool: &QueryPool, 692 queries: Range<u32>, 693 ) -> Result<(), QueryError> { 694 // VUID-vkCmdResetQueryPool-renderpass 695 if self.builder_state.render_pass.is_some() { 696 return Err(QueryError::ForbiddenInsideRenderPass); 697 } 698 699 let queue_family_properties = self.queue_family_properties(); 700 701 // VUID-vkCmdResetQueryPool-commandBuffer-cmdpool 702 if !queue_family_properties 703 .queue_flags 704 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 705 { 706 return Err(QueryError::NotSupportedByQueueFamily); 707 } 708 709 let device = self.device(); 710 711 // VUID-vkCmdResetQueryPool-commonparent 712 assert_eq!(device, query_pool.device()); 713 714 // VUID-vkCmdResetQueryPool-firstQuery-00796 715 // VUID-vkCmdResetQueryPool-firstQuery-00797 716 query_pool 717 .queries_range(queries.clone()) 718 .ok_or(QueryError::OutOfRange)?; 719 720 // VUID-vkCmdResetQueryPool-None-02841 721 if self 722 .builder_state 723 .queries 724 .values() 725 .any(|state| state.query_pool == query_pool.handle() && queries.contains(&state.query)) 726 { 727 return Err(QueryError::QueryIsActive); 728 } 729 730 Ok(()) 731 } 732 733 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] reset_query_pool_unchecked( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, ) -> &mut Self734 pub unsafe fn reset_query_pool_unchecked( 735 &mut self, 736 query_pool: Arc<QueryPool>, 737 queries: Range<u32>, 738 ) -> &mut Self { 739 let fns = self.device().fns(); 740 (fns.v1_0.cmd_reset_query_pool)( 741 self.handle(), 742 query_pool.handle(), 743 queries.start, 744 queries.end - queries.start, 745 ); 746 747 self.resources.push(Box::new(query_pool)); 748 749 self.next_command_index += 1; 750 self 751 } 752 } 753