diff --git a/examples/demo.rs b/examples/demo.rs index be108c8..c789945 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -223,9 +223,36 @@ impl ApplicationHandler<()> for State { WindowEvent::RedrawRequested => { profiling::scope!("Redraw Requested"); - let frame = surface - .get_current_texture() - .expect("Failed to acquire next surface texture"); + let mut frame; + let mut i = 0; + loop { + i += 1; + frame = match surface.get_current_texture() { + Ok(frame) => frame, + Err(err) => match err { + wgpu::SurfaceError::Timeout => { + if i > 10 { + return; + } + continue; + } + + wgpu::SurfaceError::Outdated => { + if i > 10 { + return; + } + surface.configure(&device, surface_desc); + continue; + } + + wgpu::SurfaceError::Lost | wgpu::SurfaceError::OutOfMemory => { + panic!("Failed to acquire next surface texture: {err}"); + } + }, + }; + break; + } + let frame_view = frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); @@ -334,6 +361,18 @@ fn draw( rpass.draw(0..6, 1..2); } } + + { + // You can also use traits to create your own helper functions on your scopes + let mut rpass = my_fancy_pass(&mut scope, device, view); + rpass.set_pipeline(render_pipeline); + + { + let mut rpass = rpass.scope("fractal 2", device); + rpass.draw(0..6, 2..3); + }; + } + { // It's also possible to take timings by hand, manually calling `begin_query` and `end_query`. // This is generally not recommended as it's very easy to mess up by accident :) @@ -363,9 +402,9 @@ fn draw( // Again, to do any actual timing, you need to enable wgpu::Features::TIMESTAMP_QUERY_INSIDE_PASSES. { let query = profiler - .begin_query("fractal 2", &mut rpass, device) + .begin_query("fractal 3", &mut rpass, device) .with_parent(Some(&pass_scope)); - rpass.draw(0..6, 2..3); + rpass.draw(0..6, 3..4); // Don't forget to end the query! profiler.end_query(&mut rpass, query); @@ -373,7 +412,7 @@ fn draw( // Another variant is to use `ManualOwningScope`, forming a middle ground between no scope helpers and fully automatic scope closing. let mut rpass = { let mut rpass = profiler.manual_owning_scope("fractal 3", rpass, device); - rpass.draw(0..6, 3..4); + rpass.draw(0..6, 4..5); // Don't forget to end the scope. // Ending a `ManualOwningScope` will return the pass or encoder it owned. @@ -385,6 +424,31 @@ fn draw( } } +pub fn my_fancy_pass<'b, E: wgpu_profiler::PassEncoderExt>( + e: &'b mut E, + device: &wgpu::Device, + view: &wgpu::TextureView, +) -> wgpu_profiler::OwningScope<'b, wgpu::RenderPass<'b>> { + e.scoped_render_pass( + "My Fancy Pass!", + device, + wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + ..Default::default() + }, + ) +} + fn main() { tracy_client::Client::start(); //env_logger::init_from_env(env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "warn")); diff --git a/src/lib.rs b/src/lib.rs index 1fd6a37..3a717f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,4 +115,4 @@ pub use profiler::GpuProfiler; pub use profiler_command_recorder::ProfilerCommandRecorder; pub use profiler_query::{GpuProfilerQuery, GpuTimerQueryResult}; pub use profiler_settings::GpuProfilerSettings; -pub use scope::{ManualOwningScope, OwningScope, Scope}; +pub use scope::{ManualOwningScope, OwningScope, PassEncoderExt, Scope, ScopeExt}; diff --git a/src/scope.rs b/src/scope.rs index 011743d..1af9317 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -63,6 +63,36 @@ impl<'a, R: ProfilerCommandRecorder> ManualOwningScope<'a, R> { } } +pub trait ScopeExt: + std::ops::Deref + std::ops::DerefMut +{ + /// Starts a new profiler scope nested within this one. + #[must_use] + #[track_caller] + fn scope(&mut self, label: impl Into, device: &wgpu::Device) -> Scope<'_, R>; +} + +pub trait PassEncoderExt: + std::ops::Deref + + std::ops::DerefMut + + ScopeExt +{ + #[track_caller] + fn scoped_render_pass<'a>( + &'a mut self, + label: impl Into, + device: &wgpu::Device, + pass_descriptor: wgpu::RenderPassDescriptor<'_>, + ) -> OwningScope<'a, wgpu::RenderPass<'a>>; + + #[track_caller] + fn scoped_compute_pass<'a>( + &'a mut self, + label: impl Into, + device: &wgpu::Device, + ) -> OwningScope<'a, wgpu::ComputePass<'a>>; +} + /// Most implementation code of the different scope types is exactly the same. /// /// This macro allows to avoid code duplication. @@ -93,6 +123,13 @@ macro_rules! impl_scope_ext { } } + impl<'a, R: ProfilerCommandRecorder> ScopeExt for $scope<'a, R> { + #[inline(always)] + fn scope(&mut self, label: impl Into, device: &wgpu::Device) -> Scope<'_, R> { + $scope::scope(self, label, device) + } + } + impl<'a> $scope<'a, wgpu::CommandEncoder> { /// Start a render pass wrapped in a [`OwningScope`]. /// @@ -159,6 +196,27 @@ macro_rules! impl_scope_ext { } } + impl PassEncoderExt for $scope<'_, wgpu::CommandEncoder> { + #[track_caller] + fn scoped_render_pass<'a>( + &'a mut self, + label: impl Into, + device: &wgpu::Device, + pass_descriptor: wgpu::RenderPassDescriptor<'_>, + ) -> OwningScope<'a, wgpu::RenderPass<'a>> { + $scope::scoped_render_pass(self, label, device, pass_descriptor) + } + + #[track_caller] + fn scoped_compute_pass<'a>( + &'a mut self, + label: impl Into, + device: &wgpu::Device, + ) -> OwningScope<'a, wgpu::ComputePass<'a>> { + $scope::scoped_compute_pass(self, label, device) + } + } + impl<'a, R: ProfilerCommandRecorder> std::ops::Deref for $scope<'a, R> { type Target = R;