• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use crate::buffer::TypedBufferAccess;
11 use crate::device::physical::QueueFamily;
12 use crate::device::Device;
13 use crate::device::DeviceOwned;
14 use crate::query::GetResultsError;
15 use crate::query::QueryControlFlags;
16 use crate::query::QueryPool;
17 use crate::query::QueryResultElement;
18 use crate::query::QueryResultFlags;
19 use crate::query::QueryType;
20 use crate::sync::PipelineStage;
21 use crate::DeviceSize;
22 use crate::VulkanObject;
23 use std::error;
24 use std::fmt;
25 use std::ops::Range;
26 
27 /// Checks whether a `begin_query` command is valid.
28 ///
29 /// # Panic
30 ///
31 /// - Panics if the query pool was not created with `device`.
check_begin_query( device: &Device, query_pool: &QueryPool, query: u32, flags: QueryControlFlags, ) -> Result<(), CheckBeginQueryError>32 pub fn check_begin_query(
33     device: &Device,
34     query_pool: &QueryPool,
35     query: u32,
36     flags: QueryControlFlags,
37 ) -> Result<(), CheckBeginQueryError> {
38     assert_eq!(
39         device.internal_object(),
40         query_pool.device().internal_object(),
41     );
42     query_pool
43         .query(query)
44         .ok_or(CheckBeginQueryError::OutOfRange)?;
45 
46     match query_pool.ty() {
47         QueryType::Occlusion => {
48             if flags.precise && !device.enabled_features().occlusion_query_precise {
49                 return Err(CheckBeginQueryError::OcclusionQueryPreciseFeatureNotEnabled);
50             }
51         }
52         QueryType::PipelineStatistics(_) => {
53             if flags.precise {
54                 return Err(CheckBeginQueryError::InvalidFlags);
55             }
56         }
57         QueryType::Timestamp => return Err(CheckBeginQueryError::NotPermitted),
58     }
59 
60     Ok(())
61 }
62 
63 /// Error that can happen from `check_begin_query`.
64 #[derive(Debug, Copy, Clone)]
65 pub enum CheckBeginQueryError {
66     /// The provided flags are not allowed for this type of query.
67     InvalidFlags,
68     /// This operation is not permitted on this query type.
69     NotPermitted,
70     /// `QueryControlFlags::precise` was requested, but the `occlusion_query_precise` feature was not enabled.
71     OcclusionQueryPreciseFeatureNotEnabled,
72     /// The provided query index is not valid for this pool.
73     OutOfRange,
74 }
75 
76 impl error::Error for CheckBeginQueryError {}
77 
78 impl fmt::Display for CheckBeginQueryError {
79     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>80     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
81         write!(
82             fmt,
83             "{}",
84             match *self {
85                 Self::InvalidFlags => {
86                     "the provided flags are not allowed for this type of query"
87                 }
88                 Self::NotPermitted => {
89                     "this operation is not permitted on this query type"
90                 }
91                 Self::OcclusionQueryPreciseFeatureNotEnabled => {
92                     "QueryControlFlags::precise was requested, but the occlusion_query_precise feature was not enabled"
93                 }
94                 Self::OutOfRange => {
95                     "the provided query index is not valid for this pool"
96                 }
97             }
98         )
99     }
100 }
101 
102 /// Checks whether a `end_query` command is valid.
103 ///
104 /// # Panic
105 ///
106 /// - Panics if the query pool was not created with `device`.
check_end_query( device: &Device, query_pool: &QueryPool, query: u32, ) -> Result<(), CheckEndQueryError>107 pub fn check_end_query(
108     device: &Device,
109     query_pool: &QueryPool,
110     query: u32,
111 ) -> Result<(), CheckEndQueryError> {
112     assert_eq!(
113         device.internal_object(),
114         query_pool.device().internal_object(),
115     );
116 
117     query_pool
118         .query(query)
119         .ok_or(CheckEndQueryError::OutOfRange)?;
120 
121     Ok(())
122 }
123 
124 /// Error that can happen from `check_end_query`.
125 #[derive(Debug, Copy, Clone)]
126 pub enum CheckEndQueryError {
127     /// The provided query index is not valid for this pool.
128     OutOfRange,
129 }
130 
131 impl error::Error for CheckEndQueryError {}
132 
133 impl fmt::Display for CheckEndQueryError {
134     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>135     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
136         write!(
137             fmt,
138             "{}",
139             match *self {
140                 Self::OutOfRange => {
141                     "the provided query index is not valid for this pool"
142                 }
143             }
144         )
145     }
146 }
147 
148 /// Checks whether a `write_timestamp` command is valid.
149 ///
150 /// # Panic
151 ///
152 /// - Panics if the query pool was not created with `device`.
check_write_timestamp( device: &Device, queue_family: QueueFamily, query_pool: &QueryPool, query: u32, stage: PipelineStage, ) -> Result<(), CheckWriteTimestampError>153 pub fn check_write_timestamp(
154     device: &Device,
155     queue_family: QueueFamily,
156     query_pool: &QueryPool,
157     query: u32,
158     stage: PipelineStage,
159 ) -> Result<(), CheckWriteTimestampError> {
160     assert_eq!(
161         device.internal_object(),
162         query_pool.device().internal_object(),
163     );
164 
165     if !matches!(query_pool.ty(), QueryType::Timestamp) {
166         return Err(CheckWriteTimestampError::NotPermitted);
167     }
168 
169     query_pool
170         .query(query)
171         .ok_or(CheckWriteTimestampError::OutOfRange)?;
172 
173     if queue_family.timestamp_valid_bits().is_none() {
174         return Err(CheckWriteTimestampError::NoTimestampValidBits);
175     }
176 
177     if !queue_family.supports_stage(stage) {
178         return Err(CheckWriteTimestampError::StageNotSupported);
179     }
180 
181     match stage {
182         PipelineStage::GeometryShader => {
183             if !device.enabled_features().geometry_shader {
184                 return Err(CheckWriteTimestampError::GeometryShaderFeatureNotEnabled);
185             }
186         }
187         PipelineStage::TessellationControlShader | PipelineStage::TessellationEvaluationShader => {
188             if !device.enabled_features().tessellation_shader {
189                 return Err(CheckWriteTimestampError::TessellationShaderFeatureNotEnabled);
190             }
191         }
192         _ => (),
193     }
194 
195     Ok(())
196 }
197 
198 /// Error that can happen from `check_write_timestamp`.
199 #[derive(Debug, Copy, Clone)]
200 pub enum CheckWriteTimestampError {
201     /// The geometry shader stage was requested, but the `geometry_shader` feature was not enabled.
202     GeometryShaderFeatureNotEnabled,
203     /// The queue family's `timestamp_valid_bits` value is `None`.
204     NoTimestampValidBits,
205     /// This operation is not permitted on this query type.
206     NotPermitted,
207     /// The provided query index is not valid for this pool.
208     OutOfRange,
209     /// The provided stage is not supported by the queue family.
210     StageNotSupported,
211     /// A tessellation shader stage was requested, but the `tessellation_shader` feature was not enabled.
212     TessellationShaderFeatureNotEnabled,
213 }
214 
215 impl error::Error for CheckWriteTimestampError {}
216 
217 impl fmt::Display for CheckWriteTimestampError {
218     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>219     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
220         write!(
221             fmt,
222             "{}",
223             match *self {
224                 Self::GeometryShaderFeatureNotEnabled => {
225                     "the geometry shader stage was requested, but the geometry_shader feature was not enabled"
226                 }
227                 Self::NoTimestampValidBits => {
228                     "the queue family's timestamp_valid_bits value is None"
229                 }
230                 Self::NotPermitted => {
231                     "this operation is not permitted on this query type"
232                 }
233                 Self::OutOfRange => {
234                     "the provided query index is not valid for this pool"
235                 }
236                 Self::StageNotSupported => {
237                     "the provided stage is not supported by the queue family"
238                 }
239                 Self::TessellationShaderFeatureNotEnabled => {
240                     "a tessellation shader stage was requested, but the tessellation_shader feature was not enabled"
241                 }
242             }
243         )
244     }
245 }
246 
247 /// Checks whether a `copy_query_pool_results` command is valid.
248 ///
249 /// # Panic
250 ///
251 /// - Panics if the query pool or buffer was not created with `device`.
check_copy_query_pool_results<D, T>( device: &Device, query_pool: &QueryPool, queries: Range<u32>, destination: &D, flags: QueryResultFlags, ) -> Result<DeviceSize, CheckCopyQueryPoolResultsError> where D: ?Sized + TypedBufferAccess<Content = [T]>, T: QueryResultElement,252 pub fn check_copy_query_pool_results<D, T>(
253     device: &Device,
254     query_pool: &QueryPool,
255     queries: Range<u32>,
256     destination: &D,
257     flags: QueryResultFlags,
258 ) -> Result<DeviceSize, CheckCopyQueryPoolResultsError>
259 where
260     D: ?Sized + TypedBufferAccess<Content = [T]>,
261     T: QueryResultElement,
262 {
263     let buffer_inner = destination.inner();
264     assert_eq!(
265         device.internal_object(),
266         buffer_inner.buffer.device().internal_object(),
267     );
268     assert_eq!(
269         device.internal_object(),
270         query_pool.device().internal_object(),
271     );
272 
273     if !buffer_inner.buffer.usage().transfer_destination {
274         return Err(CheckCopyQueryPoolResultsError::DestinationMissingTransferUsage);
275     }
276 
277     let queries_range = query_pool
278         .queries_range(queries)
279         .ok_or(CheckCopyQueryPoolResultsError::OutOfRange)?;
280 
281     Ok(queries_range.check_query_pool_results::<T>(
282         buffer_inner.offset,
283         destination.len(),
284         flags,
285     )?)
286 }
287 
288 /// Error that can happen from `check_copy_query_pool_results`.
289 #[derive(Debug, Copy, Clone)]
290 pub enum CheckCopyQueryPoolResultsError {
291     /// The buffer is too small for the copy operation.
292     BufferTooSmall {
293         /// Required number of elements in the buffer.
294         required_len: DeviceSize,
295         /// Actual number of elements in the buffer.
296         actual_len: DeviceSize,
297     },
298     /// The destination buffer is missing the transfer destination usage.
299     DestinationMissingTransferUsage,
300     /// The provided flags are not allowed for this type of query.
301     InvalidFlags,
302     /// The provided queries range is not valid for this pool.
303     OutOfRange,
304 }
305 
306 impl From<GetResultsError> for CheckCopyQueryPoolResultsError {
307     #[inline]
from(value: GetResultsError) -> Self308     fn from(value: GetResultsError) -> Self {
309         match value {
310             GetResultsError::BufferTooSmall {
311                 required_len,
312                 actual_len,
313             } => CheckCopyQueryPoolResultsError::BufferTooSmall {
314                 required_len,
315                 actual_len,
316             },
317             GetResultsError::InvalidFlags => CheckCopyQueryPoolResultsError::InvalidFlags,
318             GetResultsError::DeviceLost | GetResultsError::OomError(_) => unreachable!(),
319         }
320     }
321 }
322 
323 impl error::Error for CheckCopyQueryPoolResultsError {}
324 
325 impl fmt::Display for CheckCopyQueryPoolResultsError {
326     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>327     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
328         write!(
329             fmt,
330             "{}",
331             match *self {
332                 Self::BufferTooSmall { .. } => {
333                     "the buffer is too small for the copy operation"
334                 }
335                 Self::DestinationMissingTransferUsage => {
336                     "the destination buffer is missing the transfer destination usage"
337                 }
338                 Self::InvalidFlags => {
339                     "the provided flags are not allowed for this type of query"
340                 }
341                 Self::OutOfRange => {
342                     "the provided queries range is not valid for this pool"
343                 }
344             }
345         )
346     }
347 }
348 
349 /// Checks whether a `reset_query_pool` command is valid.
350 ///
351 /// # Panic
352 ///
353 /// - Panics if the query pool was not created with `device`.
check_reset_query_pool( device: &Device, query_pool: &QueryPool, queries: Range<u32>, ) -> Result<(), CheckResetQueryPoolError>354 pub fn check_reset_query_pool(
355     device: &Device,
356     query_pool: &QueryPool,
357     queries: Range<u32>,
358 ) -> Result<(), CheckResetQueryPoolError> {
359     assert_eq!(
360         device.internal_object(),
361         query_pool.device().internal_object(),
362     );
363     query_pool
364         .queries_range(queries)
365         .ok_or(CheckResetQueryPoolError::OutOfRange)?;
366     Ok(())
367 }
368 
369 /// Error that can happen from `check_reset_query_pool`.
370 #[derive(Debug, Copy, Clone)]
371 pub enum CheckResetQueryPoolError {
372     /// The provided queries range is not valid for this pool.
373     OutOfRange,
374 }
375 
376 impl error::Error for CheckResetQueryPoolError {}
377 
378 impl fmt::Display for CheckResetQueryPoolError {
379     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>380     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
381         write!(
382             fmt,
383             "{}",
384             match *self {
385                 Self::OutOfRange => {
386                     "the provided queries range is not valid for this pool"
387                 }
388             }
389         )
390     }
391 }
392