• 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 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