From a9a75435c8b138948d7939196137f75609971466 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 21 Dec 2025 11:22:46 -0800 Subject: [PATCH 1/4] Markdown fixes. --- wgpu-types/src/lib.rs | 2 +- wgpu/src/api/queue.rs | 2 +- wgpu/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8f8d76c3956..8501a6c8296 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -123,7 +123,7 @@ macro_rules! link_to_wgpu_docs { macro_rules! link_to_wgpu_item { ($kind:ident $name:ident) => { $crate::link_to_wgpu_docs!( - [concat!("`", stringify!($name), "`")]: concat!("$kind.", stringify!($name), ".html") + [concat!("`", stringify!($name), "`")]: concat!(stringify!($kind), ".", stringify!($name), ".html") ) }; } diff --git a/wgpu/src/api/queue.rs b/wgpu/src/api/queue.rs index 0e52863eb43..bbe7af205f2 100644 --- a/wgpu/src/api/queue.rs +++ b/wgpu/src/api/queue.rs @@ -267,7 +267,7 @@ impl Queue { /// /// Returns zero if timestamp queries are unsupported. /// - /// Timestamp values are represented in nanosecond values on WebGPU, see `` + /// Timestamp values are represented in nanosecond values on WebGPU, see /// Therefore, this is always 1.0 on the web, but on wgpu-core a manual conversion is required. pub fn get_timestamp_period(&self) -> f32 { self.inner.get_timestamp_period() diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 167b6f5b9e1..4202fb8ee47 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -69,7 +69,7 @@ //! complicated cases. //! //! - **`wgpu_core`** --- Enabled when there is any non-webgpu backend enabled on the platform. -//! - **`naga`** --- Enabled when target `glsl` or `spirv`` input is enabled, or when `wgpu_core` is enabled. +//! - **`naga`** --- Enabled when target `glsl` or `spirv` input is enabled, or when `wgpu_core` is enabled. //! #![no_std] From 509c7b9d1e34d97ebb6f390c4596ce7e1e3d6fbe Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Mon, 22 Dec 2025 09:19:42 -0800 Subject: [PATCH 2/4] Replace docs.rs links in `Features` with `link_to_wgpu_docs!`. --- wgpu-types/src/features.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index b978764b95b..99e173a5aeb 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -635,9 +635,9 @@ bitflags_array! { /// /// This is a native only feature with a [proposal](https://github.com/gpuweb/gpuweb/blob/0008bd30da2366af88180b511a5d0d0c1dffbc36/proposals/pipeline-statistics-query.md) for the web. /// - /// [`RenderPass::begin_pipeline_statistics_query`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.begin_pipeline_statistics_query - /// [`RenderPass::end_pipeline_statistics_query`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.end_pipeline_statistics_query - /// [`CommandEncoder::resolve_query_set`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.resolve_query_set + #[doc = link_to_wgpu_docs!(["`RenderPass::begin_pipeline_statistics_query`"]: "struct.RenderPass.html#method.begin_pipeline_statistics_query")] + #[doc = link_to_wgpu_docs!(["`RenderPass::end_pipeline_statistics_query`"]: "struct.RenderPass.html#method.end_pipeline_statistics_query")] + #[doc = link_to_wgpu_docs!(["`CommandEncoder::resolve_query_set`"]: "struct.CommandEncoder.html#method.resolve_query_set")] /// [`PipelineStatisticsTypes`]: super::PipelineStatisticsTypes const PIPELINE_STATISTICS_QUERY = 1 << 4; /// Allows for timestamp queries directly on command encoders. @@ -654,7 +654,7 @@ bitflags_array! { /// /// This is a native only feature. /// - /// [`CommandEncoder::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.write_timestamp + #[doc = link_to_wgpu_docs!(["`CommandEncoder::write_timestamp`"]: "struct.CommandEncoder.html#method.write_timestamp")] const TIMESTAMP_QUERY_INSIDE_ENCODERS = 1 << 5; /// Allows for timestamp queries directly on command encoders. /// @@ -673,8 +673,8 @@ bitflags_array! { /// /// This is a native only feature with a [proposal](https://github.com/gpuweb/gpuweb/blob/0008bd30da2366af88180b511a5d0d0c1dffbc36/proposals/timestamp-query-inside-passes.md) for the web. /// - /// [`RenderPass::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.write_timestamp - /// [`ComputePass::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.ComputePass.html#method.write_timestamp + #[doc = link_to_wgpu_docs!(["`RenderPass::write_timestamp`"]: "struct.RenderPass.html#method.write_timestamp")] + #[doc = link_to_wgpu_docs!(["`ComputePass::write_timestamp`"]: "struct.ComputePass.html#method.write_timestamp")] const TIMESTAMP_QUERY_INSIDE_PASSES = 1 << 6; /// Webgpu only allows the MAP_READ and MAP_WRITE buffer usage to be matched with /// COPY_DST and COPY_SRC respectively. This removes this requirement. @@ -1103,7 +1103,7 @@ bitflags_array! { /// This is a native only feature. /// /// [VK_GOOGLE_display_timing]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html - /// [`Surface::as_hal()`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html#method.as_hal + #[doc = link_to_wgpu_docs!(["`Surface::as_hal()`"]: "struct.Surface.html#method.as_hal")] const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 44; /// Allows using the [VK_KHR_external_memory_win32] Vulkan extension. @@ -1213,7 +1213,7 @@ bitflags_array! { /// Ideally, in the future, all platforms will be supported. For more info, see /// [this comment](https://github.com/gfx-rs/wgpu/issues/3103#issuecomment-2833058367). /// - /// [`Device::create_shader_module_passthrough`]: https://docs.rs/wgpu/latest/wgpu/struct.Device.html#method.create_shader_module_passthrough + #[doc = link_to_wgpu_docs!(["`Device::create_shader_module_passthrough`"]: "struct.Device.html#method.create_shader_module_passthrough")] const EXPERIMENTAL_PASSTHROUGH_SHADERS = 1 << 52; /// Enables shader barycentric coordinates. @@ -1425,10 +1425,10 @@ bitflags_array! { /// /// This is a web and native feature. /// - /// [`RenderPassDescriptor::timestamp_writes`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPassDescriptor.html#structfield.timestamp_writes - /// [`ComputePassDescriptor::timestamp_writes`]: https://docs.rs/wgpu/latest/wgpu/struct.ComputePassDescriptor.html#structfield.timestamp_writes - /// [`CommandEncoder::resolve_query_set`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.resolve_query_set - /// [`Queue::get_timestamp_period`]: https://docs.rs/wgpu/latest/wgpu/struct.Queue.html#method.get_timestamp_period + #[doc = link_to_wgpu_docs!(["`RenderPassDescriptor::timestamp_writes`"]: "struct.RenderPassDescriptor.html#structfield.timestamp_writes")] + #[doc = link_to_wgpu_docs!(["`ComputePassDescriptor::timestamp_writes`"]: "struct.ComputePassDescriptor.html#structfield.timestamp_writes")] + #[doc = link_to_wgpu_docs!(["`CommandEncoder::resolve_query_set`"]: "struct.CommandEncoder.html#method.resolve_query_set")] + #[doc = link_to_wgpu_docs!(["`Queue::get_timestamp_period`"]: "struct.Queue.html#method.get_timestamp_period")] const TIMESTAMP_QUERY = WEBGPU_FEATURE_TIMESTAMP_QUERY; /// Allows non-zero value for the `first_instance` member in indirect draw calls. From 5aa58584af05ad483a436ccfbba7a9603aa14b49 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 21 Dec 2025 10:22:42 -0800 Subject: [PATCH 3/4] Explain where `Device::features()` and `Device::limits()` come from. This clarifies that they are under user control and do not necessarily represent hard impossibilities. --- wgpu/src/api/device.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wgpu/src/api/device.rs b/wgpu/src/api/device.rs index 98786c8e1ea..0a817239aa0 100644 --- a/wgpu/src/api/device.rs +++ b/wgpu/src/api/device.rs @@ -96,8 +96,10 @@ impl Device { self.inner.poll(poll_type.map_index(|s| s.index)) } - /// The features which can be used on this device. + /// The [features][Features] which can be used on this device. /// + /// This will be equal to the [`required_features`][DeviceDescriptor::required_features] + /// specified when creating the device. /// No additional features can be used, even if the underlying adapter can support them. #[must_use] pub fn features(&self) -> Features { @@ -106,6 +108,8 @@ impl Device { /// The limits which can be used on this device. /// + /// This will be equal to the [`required_limits`][DeviceDescriptor::required_limits] + /// specified when creating the device. /// No better limits can be used, even if the underlying adapter can support them. #[must_use] pub fn limits(&self) -> Limits { From a2837e242e51b85f5a6f88042babf538eb805dc6 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Mon, 22 Dec 2025 09:04:28 -0800 Subject: [PATCH 4/4] 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. --- CHANGELOG.md | 6 +++ wgpu-types/src/lib.rs | 71 ++++++++++++++++++++++++++------- wgpu/src/api/command_encoder.rs | 15 +++++-- wgpu/src/api/compute_pass.rs | 5 +++ wgpu/src/api/query_set.rs | 19 ++++++++- wgpu/src/api/render_pass.rs | 5 +++ 6 files changed, 101 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d43658d5b27..f43d84da9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,12 @@ Bottom level categories: - 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). +### Documentation + +#### General + +- 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). + ## v28.0.0 (2025-12-17) ### Major Changes diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8501a6c8296..bd98d2ded9e 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -203,7 +203,7 @@ pub const IMMEDIATE_DATA_ALIGNMENT: u32 = 4; #[doc(hidden)] pub const STORAGE_BINDING_SIZE_ALIGNMENT: u32 = 4; -/// Maximum queries in a [`QuerySetDescriptor`]. +/// Maximum number of query result slots that can be requested in a [`QuerySetDescriptor`]. pub const QUERY_SET_MAX_QUERIES: u32 = 4096; /// Size in bytes of a single piece of [query] data. @@ -467,7 +467,7 @@ pub struct QuerySetDescriptor { pub label: L, /// Kind of query that this query set should contain. pub ty: QueryType, - /// Total count of queries the set contains. Must not be zero. + /// Total number of query result slots the set contains. Must not be zero. /// Must not be greater than [`QUERY_SET_MAX_QUERIES`]. pub count: u32, } @@ -484,7 +484,9 @@ impl QuerySetDescriptor { } } -/// Type of query contained in a [`QuerySet`]. +/// Type of queries contained in a [`QuerySet`]. +/// +/// Each query set may contain any number of queries, but they must all be of the same type. /// /// Corresponds to [WebGPU `GPUQueryType`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype). @@ -493,27 +495,66 @@ impl QuerySetDescriptor { #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum QueryType { - /// Query returns a single 64-bit number, serving as an occlusion boolean. - Occlusion, - /// Query returns up to 5 64-bit numbers based on the given flags. + /// An occlusion query reports whether any of the fragments drawn within the scope of the query + /// passed all per-fragment tests (i.e. were not occluded). /// - /// See [`PipelineStatisticsTypes`]'s documentation for more information - /// on how they get resolved. + /// Occlusion queries are performed by setting [`RenderPassDescriptor::occlusion_query_set`], + /// then calling [`RenderPass::begin_occlusion_query()`] and + /// [`RenderPass::end_occlusion_query()`]. + /// The query writes to a single result slot in the query set, whose value will be either 0 or 1 + /// as a boolean. /// - /// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled to use this query type. - PipelineStatistics(PipelineStatisticsTypes), - /// Query returns a 64-bit number indicating the GPU-timestamp - /// where all previous commands have finished executing. + #[doc = link_to_wgpu_docs!(["`RenderPassDescriptor::occlusion_query_set`"]: "struct.RenderPassDescriptor.html#structfield.occlusion_query_set")] + #[doc = link_to_wgpu_docs!(["`RenderPass::begin_occlusion_query()`"]: "struct.RenderPass.html#structfield.begin_occlusion_query")] + #[doc = link_to_wgpu_docs!(["`RenderPass::end_occlusion_query()`"]: "struct.RenderPass.html#structfield.end_occlusion_query")] + Occlusion, + + /// A timestamp query records a GPU-timestamp value + /// at which a certain command started or finished executing. /// - /// Must be multiplied by [`Queue::get_timestamp_period`][Qgtp] to get - /// the value in nanoseconds. Absolute values have no meaning, - /// but timestamps can be subtracted to get the time it takes + /// Timestamp queries are performed by any one of: + /// * Setting [`ComputePassDescriptor::timestamp_writes`] + /// * Setting [`RenderPassDescriptor::timestamp_writes`] + /// * Calling [`CommandEncoder::write_timestamp()`] + /// * Calling [`RenderPass::write_timestamp()`] + /// * Calling [`ComputePass::write_timestamp()`] + /// + /// Each timestamp query writes to a single result slot in the query set. + /// The timestamp value must be multiplied by [`Queue::get_timestamp_period()`][Qgtp] to get + /// the time in nanoseconds. + /// Absolute values have no meaning, but timestamps can be subtracted to get the time it takes /// for a string of operations to complete. + /// Timestamps may overflow and wrap to 0, resulting in occasional spurious negative deltas. + /// + /// Additionally, passes may be executed in parallel or out of the order they were submitted; + /// this does not affect their results but is observable via these timestamps. /// /// [`Features::TIMESTAMP_QUERY`] must be enabled to use this query type. /// + #[doc = link_to_wgpu_docs!(["`CommandEncoder::write_timestamp()`"]: "struct.CommandEncoder.html#method.write_timestamp")] + #[doc = link_to_wgpu_docs!(["`ComputePass::write_timestamp()`"]: "struct.ComputePass.html#method.write_timestamp")] + #[doc = link_to_wgpu_docs!(["`RenderPass::write_timestamp()`"]: "struct.RenderPass.html#method.write_timestamp")] + #[doc = link_to_wgpu_docs!(["`ComputePassDescriptor::timestamp_writes`"]: "struct.ComputePassDescriptor.html#structfield.timestamp_writes")] + #[doc = link_to_wgpu_docs!(["`RenderPassDescriptor::timestamp_writes`"]: "struct.RenderPassDescriptor.html#structfield.timestamp_writes")] #[doc = link_to_wgpu_docs!(["Qgtp"]: "struct.Queue.html#method.get_timestamp_period")] Timestamp, + + /// A pipeline statistics query records information about the execution of pipelines; + /// see [`PipelineStatisticsTypes`]'s documentation for details. + /// + /// Pipeline statistics queries are performed by: + /// + /// * [`ComputePass::begin_pipeline_statistics_query()`] + /// * [`RenderPass::begin_pipeline_statistics_query()`] + /// + /// A single query may occupy up to 5 result slots in the query set, based on the flags given + /// here. + /// + /// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled to use this query type. + /// + #[doc = link_to_wgpu_docs!(["`ComputePass::begin_pipeline_statistics_query()`"]: "struct.ComputePass.html#method.begin_pipeline_statistics_query")] + #[doc = link_to_wgpu_docs!(["`RenderPass::begin_pipeline_statistics_query()`"]: "struct.RenderPass.html#method.begin_pipeline_statistics_query")] + PipelineStatistics(PipelineStatisticsTypes), } bitflags::bitflags! { diff --git a/wgpu/src/api/command_encoder.rs b/wgpu/src/api/command_encoder.rs index 9f3daf06a22..ac4486ae248 100644 --- a/wgpu/src/api/command_encoder.rs +++ b/wgpu/src/api/command_encoder.rs @@ -217,12 +217,19 @@ impl CommandEncoder { self.inner.pop_debug_group(); } - /// Resolves a query set, writing the results into the supplied destination buffer. + /// Copies query results stored in `query_set` into `destination` so that they can be read + /// by compute shaders or buffer operations. /// - /// Occlusion and timestamp queries are 8 bytes each (see [`crate::QUERY_SIZE`]). For pipeline statistics queries, - /// see [`PipelineStatisticsTypes`] for more information. + /// * `query_range` is the range of query result indices to copy from `query_set`. + /// Occlusion and timestamp queries occupy 1 result index each; + /// for pipeline statistics queries, see [`PipelineStatisticsTypes`]. + /// * `destination_offset` is the offset within `destination` to start writing at. + /// It must be a multiple of [`QUERY_RESOLVE_BUFFER_ALIGNMENT`]. /// - /// `destination_offset` must be aligned to [`QUERY_RESOLVE_BUFFER_ALIGNMENT`]. + /// The length of the data written to `destination` will be 8 bytes ([`QUERY_SIZE`]) + /// times the number of elements in `query_range`. + /// + /// For further information about using queries, see [`QuerySet`]. pub fn resolve_query_set( &mut self, query_set: &QuerySet, diff --git a/wgpu/src/api/compute_pass.rs b/wgpu/src/api/compute_pass.rs index 0d1dcf58517..cbd970be922 100644 --- a/wgpu/src/api/compute_pass.rs +++ b/wgpu/src/api/compute_pass.rs @@ -143,6 +143,11 @@ impl ComputePass<'_> { impl ComputePass<'_> { /// Start a pipeline statistics query on this compute pass. It can be ended with /// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested. + /// + /// The amount of information collected by this query, and the space occupied in the query set, + /// is determined by the [`PipelineStatisticsTypes`] the query set was created with. + /// `query_index` is the index of the first query result slot that will be written to, and + /// `query_set` must have sufficient size to hold all results written starting at that slot. pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) { self.inner .begin_pipeline_statistics_query(&query_set.inner, query_index); diff --git a/wgpu/src/api/query_set.rs b/wgpu/src/api/query_set.rs index dc89330f1b9..70bd0fad268 100644 --- a/wgpu/src/api/query_set.rs +++ b/wgpu/src/api/query_set.rs @@ -2,7 +2,24 @@ use crate::*; /// Handle to a query set. /// -/// It can be created with [`Device::create_query_set`]. +/// A `QuerySet` is an opaque, mutable storage location for the results of queries: +/// which are small pieces of information extracted from other operations such as render passes. +/// See [`QueryType`] for what types of information can be collected. +/// +/// Each query writes data into one or more result slots in the `QuerySet`, which must be created +/// with a sufficient number of slots for that usage. Each result slot is a an unsigned 64-bit +/// number. +/// +/// Using queries consists of the following steps: +/// +/// 1. Create a `QuerySet` of the appropriate type and number of query result slots +/// using [`Device::create_query_set()`]. +/// 2. Pass the `QuerySet` to the commands which will write to it. +/// See [`QueryType`] for the possible commands. +/// 3. Execute the command [`CommandEncoder::resolve_query_set()`]. +/// This converts the opaque data stored in a `QuerySet` into [`u64`]s stored in a [`Buffer`]. +/// 4. Make use of that buffer, such as by copying its contents to the CPU +/// or reading it from a compute shader. /// /// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset). #[derive(Debug, Clone)] diff --git a/wgpu/src/api/render_pass.rs b/wgpu/src/api/render_pass.rs index 63416802186..3bd24d2c5f1 100644 --- a/wgpu/src/api/render_pass.rs +++ b/wgpu/src/api/render_pass.rs @@ -555,6 +555,11 @@ impl RenderPass<'_> { /// Start a pipeline statistics query on this render pass. It can be ended with /// [`end_pipeline_statistics_query`](Self::end_pipeline_statistics_query). /// Pipeline statistics queries may not be nested. + /// + /// The amount of information collected by this query, and the space occupied in the query set, + /// is determined by the [`PipelineStatisticsTypes`] the query set was created with. + /// `query_index` is the index of the first query result slot that will be written to, and + /// `query_set` must have sufficient size to hold all results written starting at that slot. pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) { self.inner .begin_pipeline_statistics_query(&query_set.inner, query_index);