Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate native-only feature for wgpu::CommandEncoder::write_timestamp #5188

Merged
merged 10 commits into from
Feb 13, 2024
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ Bottom level categories:
-wgpu::Instance::any_backend_feature_enabled()
+!wgpu::Instance::enabled_backend_features().is_empty()
```
- `wgpu::Id` now implements `PartialOrd`/`Ord` allowing it to be put in `BTreeMap`s. By @cwfitzgerald and @9291Sam in [#5176](https://github.com/gfx-rs/wgpu/pull/5176)
- `wgpu::Id` now implements `PartialOrd`/`Ord` allowing it to be put in `BTreeMap`s. By @cwfitzgerald and @9291Sam in [#5176](https://github.com/gfx-rs/wgpu/pull/5176)
- `wgpu::CommandEncoder::write_timestamp` requires now the new `wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS` feature which is available on all native backends but not on WebGPU (due to a spec change `write_timestamp` is no longer supported on WebGPU). By @wumpf in [#5188](https://github.com/gfx-rs/wgpu/pull/5188)

### Bug Fixes

Expand Down
2 changes: 1 addition & 1 deletion examples/src/mipmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const MIP_PASS_COUNT: u32 = MIP_LEVEL_COUNT - 1;

const QUERY_FEATURES: wgpu::Features = {
wgpu::Features::TIMESTAMP_QUERY
.union(wgpu::Features::PIPELINE_STATISTICS_QUERY)
.union(wgpu::Features::TIMESTAMP_QUERY_INSIDE_PASSES)
.union(wgpu::Features::PIPELINE_STATISTICS_QUERY)
};

fn create_texels(size: usize, cx: f32, cy: f32) -> Vec<u8> {
Expand Down
57 changes: 43 additions & 14 deletions examples/src/timestamp_queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
//!
//! Timestamp queries are typically used to profile how long certain operations take on the GPU.
//! wgpu has several ways of performing gpu timestamp queries:
//! * `wgpu::Encoder::write_timestamp` writes a between any commands recorded on an encoder.
//! (enabled with wgpu::Features::TIMESTAMP_QUERY)
//! * passing `wgpu::RenderPassTimestampWrites`/`wgpu::ComputePassTimestampWrites` during render/compute pass creation.
//! This writes timestamps for the beginning and end of a given pass.
//! (enabled with wgpu::Features::TIMESTAMP_QUERY)
//! * `wgpu::CommandEncoder::write_timestamp` writes a between any commands recorded on an encoder.
//! (enabled with wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)
//! * `wgpu::RenderPass/ComputePass::write_timestamp` writes a timestamp within commands of a render pass.
//! Note that some GPU architectures do not support this.
//! (native only, enabled with wgpu::Features::TIMESTAMP_QUERY_INSIDE_PASSES)
Expand Down Expand Up @@ -241,8 +241,13 @@ fn submit_render_and_compute_pass_with_queries(
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!("shader.wgsl"))),
});

encoder.write_timestamp(&queries.set, queries.next_unused_query);
queries.next_unused_query += 1;
if device
.features()
.contains(wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)
{
encoder.write_timestamp(&queries.set, queries.next_unused_query);
queries.next_unused_query += 1;
}

// Render two triangles and profile it.
render_pass(
Expand All @@ -262,8 +267,13 @@ fn submit_render_and_compute_pass_with_queries(
&mut queries.next_unused_query,
);

encoder.write_timestamp(&queries.set, queries.next_unused_query);
queries.next_unused_query += 1;
if device
.features()
.contains(wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)
{
encoder.write_timestamp(&queries.set, queries.next_unused_query);
queries.next_unused_query += 1;
}

queries.resolve(&mut encoder);
queue.submit(Some(encoder.finish()));
Expand Down Expand Up @@ -426,26 +436,44 @@ mod tests {
use super::{submit_render_and_compute_pass_with_queries, QueryResults};

#[gpu_test]
static TIMESTAMPS_ENCODER: GpuTestConfiguration = GpuTestConfiguration::new()
static TIMESTAMPS_PASS_BOUNDARIES: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
wgpu_test::TestParameters::default()
.limits(wgpu::Limits::downlevel_defaults())
.features(wgpu::Features::TIMESTAMP_QUERY),
)
.run_sync(|ctx| test_timestamps(ctx, false));
.run_sync(|ctx| test_timestamps(ctx, false, false));

#[gpu_test]
static TIMESTAMPS_ENCODER: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
wgpu_test::TestParameters::default()
.limits(wgpu::Limits::downlevel_defaults())
.features(
wgpu::Features::TIMESTAMP_QUERY
| wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS,
),
)
.run_sync(|ctx| test_timestamps(ctx, true, false));

#[gpu_test]
static TIMESTAMPS_PASSES: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
wgpu_test::TestParameters::default()
.limits(wgpu::Limits::downlevel_defaults())
.features(
wgpu::Features::TIMESTAMP_QUERY | wgpu::Features::TIMESTAMP_QUERY_INSIDE_PASSES,
wgpu::Features::TIMESTAMP_QUERY
| wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS
| wgpu::Features::TIMESTAMP_QUERY_INSIDE_PASSES,
),
)
.run_sync(|ctx| test_timestamps(ctx, true));
.run_sync(|ctx| test_timestamps(ctx, true, true));

fn test_timestamps(ctx: wgpu_test::TestingContext, timestamps_inside_passes: bool) {
fn test_timestamps(
ctx: wgpu_test::TestingContext,
timestamps_on_encoder: bool,
timestamps_inside_passes: bool,
) {
let queries = submit_render_and_compute_pass_with_queries(&ctx.device, &ctx.queue);
let raw_results = queries.wait_for_results(&ctx.device);
let QueryResults {
Expand All @@ -464,9 +492,10 @@ mod tests {
compute_start_end_timestamps[1].wrapping_sub(compute_start_end_timestamps[0]);
let encoder_delta = encoder_timestamps[1].wrapping_sub(encoder_timestamps[0]);

assert!(encoder_delta > 0);
assert!(encoder_delta >= render_delta + compute_delta);

if timestamps_on_encoder {
assert!(encoder_delta > 0);
assert!(encoder_delta >= render_delta + compute_delta);
}
if let Some(render_inside_timestamp) = render_inside_timestamp {
assert!(render_inside_timestamp >= render_start_end_timestamps[0]);
assert!(render_inside_timestamp <= render_start_end_timestamps[1]);
Expand Down
9 changes: 8 additions & 1 deletion wgpu-core/src/command/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hal::CommandEncoder as _;
use crate::device::trace::Command as TraceCommand;
use crate::{
command::{CommandBuffer, CommandEncoderError},
device::DeviceError,
device::{DeviceError, MissingFeatures},
global::Global,
hal_api::HalApi,
id::{self, Id},
Expand Down Expand Up @@ -108,6 +108,8 @@ pub enum QueryError {
Device(#[from] DeviceError),
#[error(transparent)]
Encoder(#[from] CommandEncoderError),
#[error(transparent)]
MissingFeature(#[from] MissingFeatures),
#[error("Error encountered while trying to use queries")]
Use(#[from] QueryUseError),
#[error("Error encountered while trying to resolve a query")]
Expand Down Expand Up @@ -355,6 +357,11 @@ impl Global {
let hub = A::hub(self);

let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?;

cmd_buf
.device
.require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)?;

let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();

Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ impl super::Adapter {
| wgt::Features::POLYGON_MODE_LINE
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
| wgt::Features::TIMESTAMP_QUERY
| wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS
| wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES
| wgt::Features::TEXTURE_COMPRESSION_BC
| wgt::Features::CLEAR_TEXTURE
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ impl super::Adapter {
features.set(wgt::Features::SHADER_UNUSED_VERTEX_OUTPUT, true);
if extensions.contains("GL_ARB_timer_query") {
features.set(wgt::Features::TIMESTAMP_QUERY, true);
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES, true);
}
let gl_bcn_exts = [
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/src/metal/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ impl super::PrivateCapabilities {
self.indirect_draw_dispatch,
);
features.set(
F::TIMESTAMP_QUERY,
F::TIMESTAMP_QUERY | F::TIMESTAMP_QUERY_INSIDE_ENCODERS,
self.timestamp_query_support
.contains(TimestampQuerySupport::STAGE_BOUNDARIES),
);
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ impl PhysicalDeviceFeatures {
| F::ADDRESS_MODE_CLAMP_TO_BORDER
| F::ADDRESS_MODE_CLAMP_TO_ZERO
| F::TIMESTAMP_QUERY
| F::TIMESTAMP_QUERY_INSIDE_ENCODERS
| F::TIMESTAMP_QUERY_INSIDE_PASSES
| F::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
| F::CLEAR_TEXTURE;
Expand Down
Loading
Loading