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