Skip to content

Commit 592736e

Browse files
kpreidcwfitzgerald
authored andcommitted
Expand query set documentation.
This is intended to provide all the information necessary to make use of occlusion and timestamp queries, without needing to read example code or the WebGPU spec.
1 parent 97ec4a0 commit 592736e

6 files changed

Lines changed: 101 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ Bottom level categories:
4545

4646
- Added support for cooperative load/store operations in shaders. Currently only WGSL on the input and SPIR-V, METAL, and WGSL on the output are supported. By @kvark in [#8251](https://github.com/gfx-rs/wgpu/issues/8251).
4747

48+
### Documentation
49+
50+
#### General
51+
52+
- Expanded documentation of `QuerySet`, `QueryType`, and `resolve_query_set()` describing how to use queries. By @kpreid in [#8776](https://github.com/gfx-rs/wgpu/pull/8776).
53+
4854
## v28.0.0 (2025-12-17)
4955

5056
### Major Changes

wgpu-types/src/lib.rs

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ pub const IMMEDIATE_DATA_ALIGNMENT: u32 = 4;
203203
#[doc(hidden)]
204204
pub const STORAGE_BINDING_SIZE_ALIGNMENT: u32 = 4;
205205

206-
/// Maximum queries in a [`QuerySetDescriptor`].
206+
/// Maximum number of query result slots that can be requested in a [`QuerySetDescriptor`].
207207
pub const QUERY_SET_MAX_QUERIES: u32 = 4096;
208208

209209
/// Size in bytes of a single piece of [query] data.
@@ -467,7 +467,7 @@ pub struct QuerySetDescriptor<L> {
467467
pub label: L,
468468
/// Kind of query that this query set should contain.
469469
pub ty: QueryType,
470-
/// Total count of queries the set contains. Must not be zero.
470+
/// Total number of query result slots the set contains. Must not be zero.
471471
/// Must not be greater than [`QUERY_SET_MAX_QUERIES`].
472472
pub count: u32,
473473
}
@@ -484,7 +484,9 @@ impl<L> QuerySetDescriptor<L> {
484484
}
485485
}
486486

487-
/// Type of query contained in a [`QuerySet`].
487+
/// Type of queries contained in a [`QuerySet`].
488+
///
489+
/// Each query set may contain any number of queries, but they must all be of the same type.
488490
///
489491
/// Corresponds to [WebGPU `GPUQueryType`](
490492
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype).
@@ -493,27 +495,66 @@ impl<L> QuerySetDescriptor<L> {
493495
#[derive(Copy, Clone, Debug)]
494496
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
495497
pub enum QueryType {
496-
/// Query returns a single 64-bit number, serving as an occlusion boolean.
497-
Occlusion,
498-
/// Query returns up to 5 64-bit numbers based on the given flags.
498+
/// An occlusion query reports whether any of the fragments drawn within the scope of the query
499+
/// passed all per-fragment tests (i.e. were not occluded).
499500
///
500-
/// See [`PipelineStatisticsTypes`]'s documentation for more information
501-
/// on how they get resolved.
501+
/// Occlusion queries are performed by setting [`RenderPassDescriptor::occlusion_query_set`],
502+
/// then calling [`RenderPass::begin_occlusion_query()`] and
503+
/// [`RenderPass::end_occlusion_query()`].
504+
/// The query writes to a single result slot in the query set, whose value will be either 0 or 1
505+
/// as a boolean.
502506
///
503-
/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled to use this query type.
504-
PipelineStatistics(PipelineStatisticsTypes),
505-
/// Query returns a 64-bit number indicating the GPU-timestamp
506-
/// where all previous commands have finished executing.
507+
#[doc = link_to_wgpu_docs!(["`RenderPassDescriptor::occlusion_query_set`"]: "struct.RenderPassDescriptor.html#structfield.occlusion_query_set")]
508+
#[doc = link_to_wgpu_docs!(["`RenderPass::begin_occlusion_query()`"]: "struct.RenderPass.html#structfield.begin_occlusion_query")]
509+
#[doc = link_to_wgpu_docs!(["`RenderPass::end_occlusion_query()`"]: "struct.RenderPass.html#structfield.end_occlusion_query")]
510+
Occlusion,
511+
512+
/// A timestamp query records a GPU-timestamp value
513+
/// at which a certain command started or finished executing.
507514
///
508-
/// Must be multiplied by [`Queue::get_timestamp_period`][Qgtp] to get
509-
/// the value in nanoseconds. Absolute values have no meaning,
510-
/// but timestamps can be subtracted to get the time it takes
515+
/// Timestamp queries are performed by any one of:
516+
/// * Setting [`ComputePassDescriptor::timestamp_writes`]
517+
/// * Setting [`RenderPassDescriptor::timestamp_writes`]
518+
/// * Calling [`CommandEncoder::write_timestamp()`]
519+
/// * Calling [`RenderPass::write_timestamp()`]
520+
/// * Calling [`ComputePass::write_timestamp()`]
521+
///
522+
/// Each timestamp query writes to a single result slot in the query set.
523+
/// The timestamp value must be multiplied by [`Queue::get_timestamp_period()`][Qgtp] to get
524+
/// the time in nanoseconds.
525+
/// Absolute values have no meaning, but timestamps can be subtracted to get the time it takes
511526
/// for a string of operations to complete.
527+
/// Timestamps may overflow and wrap to 0, resulting in occasional spurious negative deltas.
528+
///
529+
/// Additionally, passes may be executed in parallel or out of the order they were submitted;
530+
/// this does not affect their results but is observable via these timestamps.
512531
///
513532
/// [`Features::TIMESTAMP_QUERY`] must be enabled to use this query type.
514533
///
534+
#[doc = link_to_wgpu_docs!(["`CommandEncoder::write_timestamp()`"]: "struct.CommandEncoder.html#method.write_timestamp")]
535+
#[doc = link_to_wgpu_docs!(["`ComputePass::write_timestamp()`"]: "struct.ComputePass.html#method.write_timestamp")]
536+
#[doc = link_to_wgpu_docs!(["`RenderPass::write_timestamp()`"]: "struct.RenderPass.html#method.write_timestamp")]
537+
#[doc = link_to_wgpu_docs!(["`ComputePassDescriptor::timestamp_writes`"]: "struct.ComputePassDescriptor.html#structfield.timestamp_writes")]
538+
#[doc = link_to_wgpu_docs!(["`RenderPassDescriptor::timestamp_writes`"]: "struct.RenderPassDescriptor.html#structfield.timestamp_writes")]
515539
#[doc = link_to_wgpu_docs!(["Qgtp"]: "struct.Queue.html#method.get_timestamp_period")]
516540
Timestamp,
541+
542+
/// A pipeline statistics query records information about the execution of pipelines;
543+
/// see [`PipelineStatisticsTypes`]'s documentation for details.
544+
///
545+
/// Pipeline statistics queries are performed by:
546+
///
547+
/// * [`ComputePass::begin_pipeline_statistics_query()`]
548+
/// * [`RenderPass::begin_pipeline_statistics_query()`]
549+
///
550+
/// A single query may occupy up to 5 result slots in the query set, based on the flags given
551+
/// here.
552+
///
553+
/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled to use this query type.
554+
///
555+
#[doc = link_to_wgpu_docs!(["`ComputePass::begin_pipeline_statistics_query()`"]: "struct.ComputePass.html#method.begin_pipeline_statistics_query")]
556+
#[doc = link_to_wgpu_docs!(["`RenderPass::begin_pipeline_statistics_query()`"]: "struct.RenderPass.html#method.begin_pipeline_statistics_query")]
557+
PipelineStatistics(PipelineStatisticsTypes),
517558
}
518559

519560
bitflags::bitflags! {

wgpu/src/api/command_encoder.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,19 @@ impl CommandEncoder {
217217
self.inner.pop_debug_group();
218218
}
219219

220-
/// Resolves a query set, writing the results into the supplied destination buffer.
220+
/// Copies query results stored in `query_set` into `destination` so that they can be read
221+
/// by compute shaders or buffer operations.
221222
///
222-
/// Occlusion and timestamp queries are 8 bytes each (see [`crate::QUERY_SIZE`]). For pipeline statistics queries,
223-
/// see [`PipelineStatisticsTypes`] for more information.
223+
/// * `query_range` is the range of query result indices to copy from `query_set`.
224+
/// Occlusion and timestamp queries occupy 1 result index each;
225+
/// for pipeline statistics queries, see [`PipelineStatisticsTypes`].
226+
/// * `destination_offset` is the offset within `destination` to start writing at.
227+
/// It must be a multiple of [`QUERY_RESOLVE_BUFFER_ALIGNMENT`].
224228
///
225-
/// `destination_offset` must be aligned to [`QUERY_RESOLVE_BUFFER_ALIGNMENT`].
229+
/// The length of the data written to `destination` will be 8 bytes ([`QUERY_SIZE`])
230+
/// times the number of elements in `query_range`.
231+
///
232+
/// For further information about using queries, see [`QuerySet`].
226233
pub fn resolve_query_set(
227234
&mut self,
228235
query_set: &QuerySet,

wgpu/src/api/compute_pass.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ impl ComputePass<'_> {
143143
impl ComputePass<'_> {
144144
/// Start a pipeline statistics query on this compute pass. It can be ended with
145145
/// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
146+
///
147+
/// The amount of information collected by this query, and the space occupied in the query set,
148+
/// is determined by the [`PipelineStatisticsTypes`] the query set was created with.
149+
/// `query_index` is the index of the first query result slot that will be written to, and
150+
/// `query_set` must have sufficient size to hold all results written starting at that slot.
146151
pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
147152
self.inner
148153
.begin_pipeline_statistics_query(&query_set.inner, query_index);

wgpu/src/api/query_set.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,24 @@ use crate::*;
22

33
/// Handle to a query set.
44
///
5-
/// It can be created with [`Device::create_query_set`].
5+
/// A `QuerySet` is an opaque, mutable storage location for the results of queries:
6+
/// which are small pieces of information extracted from other operations such as render passes.
7+
/// See [`QueryType`] for what types of information can be collected.
8+
///
9+
/// Each query writes data into one or more result slots in the `QuerySet`, which must be created
10+
/// with a sufficient number of slots for that usage. Each result slot is a an unsigned 64-bit
11+
/// number.
12+
///
13+
/// Using queries consists of the following steps:
14+
///
15+
/// 1. Create a `QuerySet` of the appropriate type and number of query result slots
16+
/// using [`Device::create_query_set()`].
17+
/// 2. Pass the `QuerySet` to the commands which will write to it.
18+
/// See [`QueryType`] for the possible commands.
19+
/// 3. Execute the command [`CommandEncoder::resolve_query_set()`].
20+
/// This converts the opaque data stored in a `QuerySet` into [`u64`]s stored in a [`Buffer`].
21+
/// 4. Make use of that buffer, such as by copying its contents to the CPU
22+
/// or reading it from a compute shader.
623
///
724
/// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset).
825
#[derive(Debug, Clone)]

wgpu/src/api/render_pass.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,11 @@ impl RenderPass<'_> {
555555
/// Start a pipeline statistics query on this render pass. It can be ended with
556556
/// [`end_pipeline_statistics_query`](Self::end_pipeline_statistics_query).
557557
/// Pipeline statistics queries may not be nested.
558+
///
559+
/// The amount of information collected by this query, and the space occupied in the query set,
560+
/// is determined by the [`PipelineStatisticsTypes`] the query set was created with.
561+
/// `query_index` is the index of the first query result slot that will be written to, and
562+
/// `query_set` must have sufficient size to hold all results written starting at that slot.
558563
pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
559564
self.inner
560565
.begin_pipeline_statistics_query(&query_set.inner, query_index);

0 commit comments

Comments
 (0)