From 326ad03ce15e284e9ba280dfc523ea1aed112d56 Mon Sep 17 00:00:00 2001 From: Kevin Reid <kpreid@switchb.org> Date: Thu, 6 Mar 2025 12:27:33 -0800 Subject: [PATCH] Move `trace_dir`/`trace_path` to a custom enum inside `DeviceDescriptor`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows `wgpu` to not unconditionally depend on `std::path::Path`. It’s also, in my opinion, more user-friendly, because the feature which most users will not use (and is not currently functional) is now a defaultable struct field instead of a required parameter. The disadvantage is that `wgpu-types` now has to know about tracing. --- Cargo.lock | 1 + benches/benches/root.rs | 16 +++++----- deno_webgpu/adapter.rs | 15 ++++----- examples/features/Cargo.toml | 3 ++ examples/features/src/framework.rs | 20 ++++++------ .../features/src/hello_synchronization/mod.rs | 16 +++++----- examples/features/src/hello_triangle/mod.rs | 20 ++++++------ examples/features/src/hello_windows/mod.rs | 16 +++++----- examples/features/src/hello_workgroups/mod.rs | 16 +++++----- .../features/src/render_to_texture/mod.rs | 16 +++++----- examples/features/src/repeated_compute/mod.rs | 16 +++++----- examples/features/src/storage_texture/mod.rs | 16 +++++----- .../features/src/timestamp_queries/mod.rs | 16 +++++----- examples/features/src/uniform_values/mod.rs | 16 +++++----- .../standalone/01_hello_compute/src/main.rs | 16 +++++----- .../standalone/02_hello_window/src/main.rs | 5 +-- .../03_custom_backend/src/custom.rs | 1 - .../standalone/03_custom_backend/src/main.rs | 11 +++---- player/src/bin/play.rs | 9 ++---- player/tests/root.rs | 2 +- tests/gpu-tests/device.rs | 31 +++++++++---------- tests/src/init.rs | 16 +++++----- tests/validation-tests/root.rs | 2 +- wgpu-core/Cargo.toml | 2 +- wgpu-core/src/device/resource.rs | 31 ++++++++++++++----- wgpu-core/src/device/trace.rs | 5 ++- wgpu-core/src/instance.rs | 25 +++------------ wgpu-types/Cargo.toml | 2 ++ wgpu-types/src/lib.rs | 24 ++++++++++++++ wgpu/src/api/adapter.rs | 9 ++---- wgpu/src/backend/webgpu.rs | 5 ++- wgpu/src/backend/wgpu_core.rs | 24 +++++++++----- wgpu/src/dispatch.rs | 1 - wgpu/src/lib.rs | 2 +- 34 files changed, 209 insertions(+), 217 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 775a427d3..7db816a1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4718,6 +4718,7 @@ dependencies = [ "web-time 1.1.0", "wgpu", "wgpu-test", + "wgpu-types", "winit 0.29.15", ] diff --git a/benches/benches/root.rs b/benches/benches/root.rs index 2a8dac029..c087f1f84 100644 --- a/benches/benches/root.rs +++ b/benches/benches/root.rs @@ -43,15 +43,13 @@ impl DeviceState { eprintln!("{adapter_info:?}"); - let (device, queue) = block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - required_features: adapter.features(), - required_limits: adapter.limits(), - memory_hints: wgpu::MemoryHints::Performance, - label: Some("Compute/RenderPass Device"), - }, - None, - )) + let (device, queue) = block_on(adapter.request_device(&wgpu::DeviceDescriptor { + required_features: adapter.features(), + required_limits: adapter.limits(), + memory_hints: wgpu::MemoryHints::Performance, + label: Some("Compute/RenderPass Device"), + trace: wgpu::Trace::Off, + })) .unwrap(); Self { diff --git a/deno_webgpu/adapter.rs b/deno_webgpu/adapter.rs index ffa8827b3..169c9d60c 100644 --- a/deno_webgpu/adapter.rs +++ b/deno_webgpu/adapter.rs @@ -128,6 +128,8 @@ impl GPUAdapter { let required_limits = serde_json::from_value(serde_json::to_value(descriptor.required_limits)?)?; + let webgpu_trace = std::env::var_os("DENO_WEBGPU_TRACE").unwrap(); + let wgpu_descriptor = wgpu_types::DeviceDescriptor { label: crate::transform_label(descriptor.label.clone()), required_features: super::webidl::feature_names_to_features( @@ -135,17 +137,12 @@ impl GPUAdapter { ), required_limits, memory_hints: Default::default(), + trace: wgpu_types::Trace::Directory(std::path::PathBuf::from(webgpu_trace)), }; - let webgpu_trace = std::env::var("DENO_WEBGPU_TRACE").unwrap(); - - let (device, queue) = self.instance.adapter_request_device( - self.id, - &wgpu_descriptor, - Some(webgpu_trace.as_str()), - None, - None, - )?; + let (device, queue) = + self.instance + .adapter_request_device(self.id, &wgpu_descriptor, None, None)?; let (lost_sender, lost_receiver) = tokio::sync::oneshot::channel(); let (uncaptured_sender, mut uncaptured_receiver) = tokio::sync::mpsc::unbounded_channel(); diff --git a/examples/features/Cargo.toml b/examples/features/Cargo.toml index 11cf6b211..ec79438af 100644 --- a/examples/features/Cargo.toml +++ b/examples/features/Cargo.toml @@ -45,6 +45,9 @@ png.workspace = true pollster.workspace = true web-time.workspace = true wgpu.workspace = true +wgpu-types = { workspace = true, features = [ + "trace", # TODO(#5974): this should be a dep on wgpu/trace and not wgpu-types at all +] } winit.workspace = true [dev-dependencies] diff --git a/examples/features/src/framework.rs b/examples/features/src/framework.rs index 100e872b6..d52c3b84e 100644 --- a/examples/features/src/framework.rs +++ b/examples/features/src/framework.rs @@ -281,18 +281,18 @@ impl ExampleContext { // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface. let needed_limits = E::required_limits().using_resolution(adapter.limits()); - let trace_dir = std::env::var("WGPU_TRACE"); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: (E::optional_features() & adapter.features()) - | E::required_features(), - required_limits: needed_limits, - memory_hints: wgpu::MemoryHints::MemoryUsage, + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: (E::optional_features() & adapter.features()) + | E::required_features(), + required_limits: needed_limits, + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: match std::env::var_os("WGPU_TRACE") { + Some(path) => wgpu::Trace::Directory(path.into()), + None => wgpu::Trace::Off, }, - trace_dir.ok().as_ref().map(std::path::Path::new), - ) + }) .await .expect("Unable to find a suitable GPU adapter!"); diff --git a/examples/features/src/hello_synchronization/mod.rs b/examples/features/src/hello_synchronization/mod.rs index 737aed750..41d51acd5 100644 --- a/examples/features/src/hello_synchronization/mod.rs +++ b/examples/features/src/hello_synchronization/mod.rs @@ -12,15 +12,13 @@ async fn run() { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::Performance, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::Performance, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/hello_triangle/mod.rs b/examples/features/src/hello_triangle/mod.rs index cc65c3a89..cba78face 100644 --- a/examples/features/src/hello_triangle/mod.rs +++ b/examples/features/src/hello_triangle/mod.rs @@ -25,17 +25,15 @@ async fn run(event_loop: EventLoop<()>, window: Window) { // Create the logical device and command queue let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain. - required_limits: wgpu::Limits::downlevel_webgl2_defaults() - .using_resolution(adapter.limits()), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain. + required_limits: wgpu::Limits::downlevel_webgl2_defaults() + .using_resolution(adapter.limits()), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .expect("Failed to create device"); diff --git a/examples/features/src/hello_windows/mod.rs b/examples/features/src/hello_windows/mod.rs index d4aa994ab..2fb24a081 100644 --- a/examples/features/src/hello_windows/mod.rs +++ b/examples/features/src/hello_windows/mod.rs @@ -70,15 +70,13 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Arc<Window>, wgpu::Color // Create the logical device and command queue let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .expect("Failed to create device"); diff --git a/examples/features/src/hello_workgroups/mod.rs b/examples/features/src/hello_workgroups/mod.rs index cdddfe98a..5a8e7ffab 100644 --- a/examples/features/src/hello_workgroups/mod.rs +++ b/examples/features/src/hello_workgroups/mod.rs @@ -27,15 +27,13 @@ async fn run() { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/render_to_texture/mod.rs b/examples/features/src/render_to_texture/mod.rs index eb25d3616..917ac7310 100644 --- a/examples/features/src/render_to_texture/mod.rs +++ b/examples/features/src/render_to_texture/mod.rs @@ -16,15 +16,13 @@ async fn run(_path: Option<String>) { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/repeated_compute/mod.rs b/examples/features/src/repeated_compute/mod.rs index a31a456e6..2b9b19995 100644 --- a/examples/features/src/repeated_compute/mod.rs +++ b/examples/features/src/repeated_compute/mod.rs @@ -158,15 +158,13 @@ impl WgpuContext { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::Performance, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::Performance, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/storage_texture/mod.rs b/examples/features/src/storage_texture/mod.rs index 542ea7b84..b028e09a9 100644 --- a/examples/features/src/storage_texture/mod.rs +++ b/examples/features/src/storage_texture/mod.rs @@ -30,15 +30,13 @@ async fn run(_path: Option<String>) { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/timestamp_queries/mod.rs b/examples/features/src/timestamp_queries/mod.rs index ef2b89cbc..7bac87e1a 100644 --- a/examples/features/src/timestamp_queries/mod.rs +++ b/examples/features/src/timestamp_queries/mod.rs @@ -206,15 +206,13 @@ async fn run() { // `request_device` instantiates the feature specific connection to the GPU, defining some parameters, // `features` being the available features. let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: features, - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: features, + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/features/src/uniform_values/mod.rs b/examples/features/src/uniform_values/mod.rs index 72bac0fa5..3a6933bf1 100644 --- a/examples/features/src/uniform_values/mod.rs +++ b/examples/features/src/uniform_values/mod.rs @@ -110,15 +110,13 @@ impl WgpuContext { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await .unwrap(); diff --git a/examples/standalone/01_hello_compute/src/main.rs b/examples/standalone/01_hello_compute/src/main.rs index 71f9d2b9b..19d95620c 100644 --- a/examples/standalone/01_hello_compute/src/main.rs +++ b/examples/standalone/01_hello_compute/src/main.rs @@ -66,15 +66,13 @@ fn main() { // // The `Device` is used to create and manage GPU resources. // The `Queue` is a queue used to submit work for the GPU to process. - let (device, queue) = pollster::block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::downlevel_defaults(), - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - )) + let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_defaults(), + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + })) .expect("Failed to create device"); // Create a shader module from our shader code. This will parse and validate the shader. diff --git a/examples/standalone/02_hello_window/src/main.rs b/examples/standalone/02_hello_window/src/main.rs index 07f90d1fa..83687e281 100644 --- a/examples/standalone/02_hello_window/src/main.rs +++ b/examples/standalone/02_hello_window/src/main.rs @@ -24,10 +24,7 @@ impl State { .await .unwrap(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor::default(), - None, // Trace path - ) + .request_device(&wgpu::DeviceDescriptor::default()) .await .unwrap(); diff --git a/examples/standalone/03_custom_backend/src/custom.rs b/examples/standalone/03_custom_backend/src/custom.rs index 33cf49f69..556a1d29d 100644 --- a/examples/standalone/03_custom_backend/src/custom.rs +++ b/examples/standalone/03_custom_backend/src/custom.rs @@ -64,7 +64,6 @@ impl AdapterInterface for CustomAdapter { fn request_device( &self, desc: &wgpu::DeviceDescriptor<'_>, - _trace_dir: Option<&std::path::Path>, ) -> Pin<Box<dyn wgpu::custom::RequestDeviceFuture>> { assert_eq!(desc.label, Some("device")); let res: Result<_, wgpu::RequestDeviceError> = Ok(( diff --git a/examples/standalone/03_custom_backend/src/main.rs b/examples/standalone/03_custom_backend/src/main.rs index ed6c0b4fb..11f05e98e 100644 --- a/examples/standalone/03_custom_backend/src/main.rs +++ b/examples/standalone/03_custom_backend/src/main.rs @@ -23,13 +23,10 @@ async fn main() { assert_eq!(counter.count(), 3); let (device, _queue) = adapter - .request_device( - &DeviceDescriptor { - label: Some("device"), - ..Default::default() - }, - None, - ) + .request_device(&DeviceDescriptor { + label: Some("device"), + ..Default::default() + }) .await .unwrap(); assert_eq!(counter.count(), 5); diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 936e4a34c..1e76cb2fd 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -86,13 +86,8 @@ fn main() { log::info!("Picked '{}'", info.name); let device_id = wgc::id::Id::zip(0, 1); let queue_id = wgc::id::Id::zip(0, 1); - let res = global.adapter_request_device( - adapter, - &desc, - None, - Some(device_id), - Some(queue_id), - ); + let res = + global.adapter_request_device(adapter, &desc, Some(device_id), Some(queue_id)); if let Err(e) = res { panic!("{e:?}"); } diff --git a/player/tests/root.rs b/player/tests/root.rs index 1254a7032..44491a5f4 100644 --- a/player/tests/root.rs +++ b/player/tests/root.rs @@ -95,8 +95,8 @@ impl Test<'_> { required_features: self.features, required_limits: wgt::Limits::default(), memory_hints: wgt::MemoryHints::default(), + trace: wgt::Trace::Off, }, - None, Some(device_id), Some(queue_id), ); diff --git a/tests/gpu-tests/device.rs b/tests/gpu-tests/device.rs index 223f939db..9e03f92ac 100644 --- a/tests/gpu-tests/device.rs +++ b/tests/gpu-tests/device.rs @@ -11,7 +11,7 @@ static CROSS_DEVICE_BIND_GROUP_USAGE: GpuTestConfiguration = GpuTestConfiguratio // Create a bind group using a layout from another device. This should be a validation // error but currently crashes. let (device2, _) = - pollster::block_on(ctx.adapter.request_device(&Default::default(), None)).unwrap(); + pollster::block_on(ctx.adapter.request_device(&Default::default())).unwrap(); { let bind_group_layout = @@ -64,11 +64,11 @@ static MULTIPLE_DEVICES: GpuTestConfiguration = GpuTestConfiguration::new() .run_sync(|ctx| { use pollster::FutureExt as _; ctx.adapter - .request_device(&wgpu::DeviceDescriptor::default(), None) + .request_device(&wgpu::DeviceDescriptor::default()) .block_on() .expect("failed to create device"); ctx.adapter - .request_device(&wgpu::DeviceDescriptor::default(), None) + .request_device(&wgpu::DeviceDescriptor::default()) .block_on() .expect("failed to create device"); }); @@ -105,22 +105,19 @@ async fn request_device_error_message() { let (_instance, adapter, _surface_guard) = wgpu_test::initialize_adapter(None, false).await; let device_error = adapter - .request_device( - &wgpu::DeviceDescriptor { - // Force a failure by requesting absurd limits. - required_features: wgpu::Features::all(), - required_limits: wgpu::Limits { - max_texture_dimension_1d: u32::MAX, - max_texture_dimension_2d: u32::MAX, - max_texture_dimension_3d: u32::MAX, - max_bind_groups: u32::MAX, - max_push_constant_size: u32::MAX, - ..Default::default() - }, + .request_device(&wgpu::DeviceDescriptor { + // Force a failure by requesting absurd limits. + required_features: wgpu::Features::all(), + required_limits: wgpu::Limits { + max_texture_dimension_1d: u32::MAX, + max_texture_dimension_2d: u32::MAX, + max_texture_dimension_3d: u32::MAX, + max_bind_groups: u32::MAX, + max_push_constant_size: u32::MAX, ..Default::default() }, - None, - ) + ..Default::default() + }) .await .unwrap_err(); diff --git a/tests/src/init.rs b/tests/src/init.rs index 0553ee212..79dea24b0 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -142,15 +142,13 @@ pub async fn initialize_device( limits: Limits, ) -> (Device, Queue) { let bundle = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: features, - required_limits: limits, - memory_hints: wgpu::MemoryHints::MemoryUsage, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: features, + required_limits: limits, + memory_hints: wgpu::MemoryHints::MemoryUsage, + trace: wgpu::Trace::Off, + }) .await; match bundle { diff --git a/tests/validation-tests/root.rs b/tests/validation-tests/root.rs index a0f303abe..7227355a6 100644 --- a/tests/validation-tests/root.rs +++ b/tests/validation-tests/root.rs @@ -24,5 +24,5 @@ fn request_noop_device_with_desc(desc: &wgpu::DeviceDescriptor) -> (wgpu::Device .expect("adapter"); assert_eq!(adapter.get_info().backend, wgpu::Backend::Noop); - pollster::block_on(adapter.request_device(desc, None)).expect("device") + pollster::block_on(adapter.request_device(desc)).expect("device") } diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index d5109c277..435fb358e 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -76,7 +76,7 @@ observe_locks = ["std", "dep:ron", "serde/serde_derive"] serde = ["dep:serde", "wgpu-types/serde", "arrayvec/serde", "hashbrown/serde"] ## Enable API tracing. -trace = ["serde", "std", "dep:ron", "naga/serialize"] +trace = ["serde", "std", "dep:ron", "naga/serialize", "wgpu-types/trace"] ## Enable API replaying replay = ["serde", "naga/deserialize"] diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index bd19a20bf..740d10cfb 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -200,13 +200,27 @@ impl Device { raw_device: Box<dyn hal::DynDevice>, adapter: &Arc<Adapter>, desc: &DeviceDescriptor, - trace_dir_name: Option<&str>, instance_flags: wgt::InstanceFlags, ) -> Result<Self, DeviceError> { #[cfg(not(feature = "trace"))] - if let Some(_) = trace_dir_name { - log::error!("Feature 'trace' is not enabled"); - } + match &desc.trace { + wgt::Trace::Off => {} + _ => { + log::error!("wgpu-core feature 'trace' is not enabled"); + } + }; + #[cfg(feature = "trace")] + let trace_dir_name: Option<&std::path::PathBuf> = match &desc.trace { + wgt::Trace::Off => None, + wgt::Trace::Directory(d) => Some(d), + // The enum is non_exhaustive, so we must have a fallback arm (that should be + // unreachable in practice). + t => { + log::error!("unimplemented wgpu_types::Trace variant {t:?}"); + None + } + }; + let fence = unsafe { raw_device.create_fence() }.map_err(DeviceError::from_hal)?; let command_allocator = command::CommandAllocator::new(); @@ -272,16 +286,19 @@ impl Device { #[cfg(feature = "trace")] trace: Mutex::new( rank::DEVICE_TRACE, - trace_dir_name.and_then(|dir_path_name| match trace::Trace::new(dir_path_name) { + trace_dir_name.and_then(|path| match trace::Trace::new(path.clone()) { Ok(mut trace) => { trace.add(trace::Action::Init { - desc: desc.clone(), + desc: wgt::DeviceDescriptor { + trace: wgt::Trace::Off, + ..desc.clone() + }, backend: adapter.backend(), }); Some(trace) } Err(e) => { - log::error!("Unable to start a trace in '{dir_path_name:?}': {e}"); + log::error!("Unable to start a trace in '{path:?}': {e}"); None } }), diff --git a/wgpu-core/src/device/trace.rs b/wgpu-core/src/device/trace.rs index 421b07b2c..3932d4086 100644 --- a/wgpu-core/src/device/trace.rs +++ b/wgpu-core/src/device/trace.rs @@ -223,13 +223,12 @@ pub struct Trace { #[cfg(feature = "trace")] impl Trace { - pub fn new(dir_path_name: &str) -> Result<Self, std::io::Error> { - let path = std::path::Path::new(dir_path_name); + pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> { log::info!("Tracing into '{:?}'", path); let mut file = std::fs::File::create(path.join(FILE_NAME))?; file.write_all(b"[\n")?; Ok(Self { - path: path.to_path_buf(), + path, file, config: ron::ser::PrettyConfig::default(), binary_id: 0, diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index ab2f62e9a..e322b24ab 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -690,17 +690,10 @@ impl Adapter { hal_device: hal::DynOpenDevice, desc: &DeviceDescriptor, instance_flags: wgt::InstanceFlags, - trace_dir_name: Option<&str>, ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> { api_log!("Adapter::create_device"); - let device = Device::new( - hal_device.device, - self, - desc, - trace_dir_name, - instance_flags, - )?; + let device = Device::new(hal_device.device, self, desc, instance_flags)?; let device = Arc::new(device); let queue = Queue::new(device.clone(), hal_device.queue)?; @@ -715,7 +708,6 @@ impl Adapter { self: &Arc<Self>, desc: &DeviceDescriptor, instance_flags: wgt::InstanceFlags, - trace_dir_name: Option<&str>, ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> { // Verify all features were exposed by the adapter if !self.raw.features.contains(desc.required_features) { @@ -762,7 +754,7 @@ impl Adapter { } .map_err(DeviceError::from_hal)?; - self.create_device_and_queue_from_hal(open, desc, instance_flags, trace_dir_name) + self.create_device_and_queue_from_hal(open, desc, instance_flags) } } @@ -1039,7 +1031,6 @@ impl Global { &self, adapter_id: AdapterId, desc: &DeviceDescriptor, - trace_dir_name: Option<&str>, device_id_in: Option<DeviceId>, queue_id_in: Option<QueueId>, ) -> Result<(DeviceId, QueueId), RequestDeviceError> { @@ -1050,8 +1041,7 @@ impl Global { let queue_fid = self.hub.queues.prepare(queue_id_in); let adapter = self.hub.adapters.get(adapter_id); - let (device, queue) = - adapter.create_device_and_queue(desc, self.instance.flags, trace_dir_name)?; + let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?; let device_id = device_fid.assign(device); resource_log!("Created Device {:?}", device_id); @@ -1071,7 +1061,6 @@ impl Global { adapter_id: AdapterId, hal_device: hal::DynOpenDevice, desc: &DeviceDescriptor, - trace_dir_name: Option<&str>, device_id_in: Option<DeviceId>, queue_id_in: Option<QueueId>, ) -> Result<(DeviceId, QueueId), RequestDeviceError> { @@ -1081,12 +1070,8 @@ impl Global { let queues_fid = self.hub.queues.prepare(queue_id_in); let adapter = self.hub.adapters.get(adapter_id); - let (device, queue) = adapter.create_device_and_queue_from_hal( - hal_device, - desc, - self.instance.flags, - trace_dir_name, - )?; + let (device, queue) = + adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?; let device_id = devices_fid.assign(device); resource_log!("Created Device {:?}", device_id); diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 26734a331..d9d024a90 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -43,6 +43,8 @@ fragile-send-sync-non-atomic-wasm = [] serde = ["dep:serde", "bitflags/serde"] # Enables some internal instrumentation for debugging purposes. counters = [] +# Enables variants of `Trace` other than `Trace::Off` +trace = ["std"] [dependencies] bitflags = { workspace = true, features = ["serde"] } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 334894a20..c6dc50c5a 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1148,6 +1148,9 @@ pub struct DeviceDescriptor<L> { pub required_limits: Limits, /// Hints for memory allocation strategies. pub memory_hints: MemoryHints, + /// Whether API tracing for debugging is enabled, + /// and where the trace is written if so. + pub trace: Trace, } impl<L> DeviceDescriptor<L> { @@ -1159,10 +1162,31 @@ impl<L> DeviceDescriptor<L> { required_features: self.required_features, required_limits: self.required_limits.clone(), memory_hints: self.memory_hints.clone(), + trace: self.trace.clone(), } } } +/// Controls API call tracing and specifies where the trace is written. +/// +/// **Note:** Tracing is currently unavailable. +/// See [issue 5974](https://github.com/gfx-rs/wgpu/issues/5974) for updates. +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +// This enum must be non-exhaustive so that enabling the "trace" feature is not a semver break. +#[non_exhaustive] +pub enum Trace { + /// Tracing disabled. + #[default] + Off, + + /// Tracing enabled. + #[cfg(feature = "trace")] + // This must be owned rather than `&'a Path`, because if it were that, then the lifetime + // parameter would be unused when the "trace" feature is disabled, which is prohibited. + Directory(std::path::PathBuf), +} + bitflags::bitflags! { /// Describes the shader stages that a binding will be visible from. /// diff --git a/wgpu/src/api/adapter.rs b/wgpu/src/api/adapter.rs index 40689b6f9..614f43bae 100644 --- a/wgpu/src/api/adapter.rs +++ b/wgpu/src/api/adapter.rs @@ -46,8 +46,7 @@ impl Adapter { /// # Arguments /// /// - `desc` - Description of the features and limits requested from the given device. - /// - `trace_path` - Can be used for API call tracing, if that feature is - /// enabled in `wgpu-core`. + /// - `trace` - Can be used for API call tracing, if the feature is enabled. /// /// # Panics /// @@ -61,9 +60,8 @@ impl Adapter { pub fn request_device( &self, desc: &DeviceDescriptor<'_>, - trace_path: Option<&std::path::Path>, ) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + WasmNotSend { - let device = self.inner.request_device(desc, trace_path); + let device = self.inner.request_device(desc); async move { device .await @@ -82,13 +80,12 @@ impl Adapter { &self, hal_device: hal::OpenDevice<A>, desc: &DeviceDescriptor<'_>, - trace_path: Option<&std::path::Path>, ) -> Result<(Device, Queue), RequestDeviceError> { let core_adapter = self.inner.as_core(); let (device, queue) = unsafe { core_adapter .context - .create_device_from_hal(core_adapter, hal_device, desc, trace_path) + .create_device_from_hal(core_adapter, hal_device, desc) }?; Ok(( diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index da2388981..710cc38cc 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1591,10 +1591,9 @@ impl dispatch::AdapterInterface for WebAdapter { fn request_device( &self, desc: &crate::DeviceDescriptor<'_>, - trace_dir: Option<&std::path::Path>, ) -> Pin<Box<dyn dispatch::RequestDeviceFuture>> { - if trace_dir.is_some() { - //Error: Tracing isn't supported on the Web target + if !matches!(desc.trace, wgt::Trace::Off) { + log::warn!("The `trace` parameter is not supported on the WebGPU backend."); } let mapped_desc = webgpu_sys::GpuDeviceDescriptor::new(); diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 2a8925f47..53717bea2 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -104,11 +104,16 @@ impl ContextWgpuCore { adapter: &CoreAdapter, hal_device: hal::OpenDevice<A>, desc: &crate::DeviceDescriptor<'_>, - trace_dir: Option<&std::path::Path>, ) -> Result<(CoreDevice, CoreQueue), crate::RequestDeviceError> { - if trace_dir.is_some() { - log::error!("Feature 'trace' has been removed temporarily, see https://github.com/gfx-rs/wgpu/issues/5974"); + if !matches!(desc.trace, wgt::Trace::Off) { + log::error!( + " + Feature 'trace' has been removed temporarily; \ + see https://github.com/gfx-rs/wgpu/issues/5974. \ + The `trace` parameter will have no effect." + ); } + let (device_id, queue_id) = unsafe { self.0.create_device_from_hal( adapter.id, @@ -116,7 +121,6 @@ impl ContextWgpuCore { &desc.map_label(|l| l.map(Borrowed)), None, None, - None, ) }?; let error_sink = Arc::new(Mutex::new(ErrorSinkRaw::new())); @@ -876,17 +880,21 @@ impl dispatch::AdapterInterface for CoreAdapter { fn request_device( &self, desc: &crate::DeviceDescriptor<'_>, - trace_dir: Option<&std::path::Path>, ) -> Pin<Box<dyn dispatch::RequestDeviceFuture>> { - if trace_dir.is_some() { - log::error!("Feature 'trace' has been removed temporarily, see https://github.com/gfx-rs/wgpu/issues/5974"); + if !matches!(desc.trace, wgt::Trace::Off) { + log::error!( + " + Feature 'trace' has been removed temporarily; \ + see https://github.com/gfx-rs/wgpu/issues/5974. \ + The `trace` parameter will have no effect." + ); } + let res = self.context.0.adapter_request_device( self.id, &desc.map_label(|l| l.map(Borrowed)), None, None, - None, ); let (device_id, queue_id) = match res { Ok(ids) => ids, diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index a3bc4fafa..6c47eb48c 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -82,7 +82,6 @@ pub trait AdapterInterface: CommonTraits { fn request_device( &self, desc: &crate::DeviceDescriptor<'_>, - trace_dir: Option<&std::path::Path>, ) -> Pin<Box<dyn RequestDeviceFuture>>; fn is_surface_supported(&self, surface: &DispatchSurface) -> bool; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index ec09984b6..7dfa47f22 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -85,7 +85,7 @@ pub use wgt::{ StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TexelCopyBufferLayout, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureTransition, - TextureUsages, TextureUses, TextureViewDimension, VertexAttribute, VertexFormat, + TextureUsages, TextureUses, TextureViewDimension, Trace, VertexAttribute, VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT,