• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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