diff --git a/Cargo.toml b/Cargo.toml index f9f8800..62333da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wgpu-profiler" -version = "0.15.0" +version = "0.16.0" authors = ["Andreas Reich "] edition = "2021" description = "Simple profiler scopes for wgpu using timer queries" @@ -15,13 +15,13 @@ tracy = ["tracy-client", "profiling/profile-with-tracy"] [lib] [dependencies] -parking_lot = "0.12" # Note that wgpu already depends on parking_lot as well, so this doesn't add much. +parking_lot = "0.12" # Note that wgpu already depends on parking_lot as well, so this doesn't add much. thiserror = "1" tracy-client = { version = "0.16", optional = true } -wgpu = "0.18" +wgpu = "0.19" [dev-dependencies] -futures-lite = "1" +futures-lite = "2" profiling = { version = "1" } tracy-client = "0.16.1" -winit = "0.28" +winit = "0.29" diff --git a/README.md b/README.md index 6419a16..99bab5b 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,8 @@ for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. ## Changelog -* unreleased +* 0.16 + * update to wgpu 0.19 * ⚠️ Includes many major breaking changes! ⚠️ * `GpuProfiler` can now be used with several command buffers interleaved or in parallel! * `Scope`/`OwningScope`/`ManualScope`/ are now all top-level in the `gpu_profiler` module. `GpuProfiler` has utilities to create them directly. diff --git a/examples/demo.rs b/examples/demo.rs index ec36231..02a8444 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,8 +1,9 @@ use std::borrow::Cow; use wgpu_profiler::{GpuProfiler, GpuProfilerSettings, GpuTimerQueryResult}; use winit::{ - event::{Event, VirtualKeyCode, WindowEvent}, + event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::{KeyCode, PhysicalKey}, window::Window, }; @@ -44,9 +45,12 @@ fn console_output(results: &Option>, enabled_features: } async fn run(event_loop: EventLoop<()>, window: Window) { + let window = std::sync::Arc::new(window); let size = window.inner_size(); let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default()); - let surface = unsafe { instance.create_surface(&window) }.expect("Failed to create surface."); + let surface = instance + .create_surface(window.clone()) + .expect("Failed to create surface."); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -62,8 +66,8 @@ async fn run(event_loop: EventLoop<()>, window: Window) { .request_device( &wgpu::DeviceDescriptor { label: None, - features: adapter.features() & GpuProfiler::ALL_WGPU_TIMER_FEATURES, - limits: wgpu::Limits::default(), + required_features: adapter.features() & GpuProfiler::ALL_WGPU_TIMER_FEATURES, + required_limits: wgpu::Limits::default(), }, None, ) @@ -81,7 +85,16 @@ async fn run(event_loop: EventLoop<()>, window: Window) { push_constant_ranges: &[], }); - let swapchain_format = *surface.get_capabilities(&adapter).formats.first().unwrap(); + let mut sc_desc = wgpu::SurfaceConfiguration { + // By using the Fifo mode we ensure that CPU waits for GPU, thus we won't have an arbitrary amount of frames in flight that may be discarded. + // Profiler works just fine in any other mode, but keep in mind that this can mean that it would need to buffer up many more frames until the first results are back. + present_mode: wgpu::PresentMode::Immediate, + ..surface + .get_default_config(&adapter, size.width, size.height) + .unwrap() + }; + + let swapchain_format = sc_desc.format; let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, @@ -102,20 +115,6 @@ async fn run(event_loop: EventLoop<()>, window: Window) { multiview: None, }); - let mut sc_desc = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: swapchain_format, - width: size.width, - height: size.height, - // By using the Fifo mode we ensure that CPU waits for GPU, thus we won't have an arbitrary amount of frames in flight that may be discarded. - // Profiler works just fine in any other mode, but keep in mind that this can mean that it would need to buffer up many more frames until the first results are back. - present_mode: wgpu::PresentMode::Immediate, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: vec![swapchain_format], - }; - - surface.configure(&device, &sc_desc); - // Create a new profiler instance. #[cfg(feature = "tracy")] let mut profiler = GpuProfiler::new_with_tracy_client( @@ -139,100 +138,108 @@ async fn run(event_loop: EventLoop<()>, window: Window) { let mut latest_profiler_results = None; - event_loop.run(move |event, _, control_flow| { - // Have the closure take ownership of the resources. - // `event_loop.run` never returns, therefore we must do this to ensure - // the resources are properly cleaned up. - let _ = (&instance, &adapter, &shader, &pipeline_layout); - - *control_flow = ControlFlow::Poll; - match event { - Event::WindowEvent { - event: WindowEvent::Resized(size), - .. - } => { - if size.width > 0 && size.height > 0 { - sc_desc.width = size.width; - sc_desc.height = size.height; - surface.configure(&device, &sc_desc); - } - } - Event::MainEventsCleared => { - // Continuos rendering! - window.request_redraw(); - } - Event::RedrawRequested(_) => { - profiling::scope!("Redraw Requested"); - - let frame = surface - .get_current_texture() - .expect("Failed to acquire next surface texture"); - let frame_view = frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - - draw( - &profiler, - &mut encoder, - &frame_view, - &device, - &render_pipeline, - ); - - // Resolves any queries that might be in flight. - profiler.resolve_queries(&mut encoder); - - { - profiling::scope!("Submit"); - queue.submit(Some(encoder.finish())); + event_loop + .run(move |event, target| { + // Have the closure take ownership of the resources. + // `event_loop.run` never returns, therefore we must do this to ensure + // the resources are properly cleaned up. + let _ = (&instance, &adapter, &shader, &pipeline_layout); + + target.set_control_flow(ControlFlow::Poll); + match event { + Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + if size.width > 0 && size.height > 0 { + sc_desc.width = size.width; + sc_desc.height = size.height; + surface.configure(&device, &sc_desc); + } } - { - profiling::scope!("Present"); - frame.present(); + Event::AboutToWait => { + // Continuos rendering! + window.request_redraw(); } + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + } => { + profiling::scope!("Redraw Requested"); + + let frame = surface + .get_current_texture() + .expect("Failed to acquire next surface texture"); + let frame_view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + draw( + &profiler, + &mut encoder, + &frame_view, + &device, + &render_pipeline, + ); + + // Resolves any queries that might be in flight. + profiler.resolve_queries(&mut encoder); + + { + profiling::scope!("Submit"); + queue.submit(Some(encoder.finish())); + } + { + profiling::scope!("Present"); + frame.present(); + } - profiling::finish_frame!(); + profiling::finish_frame!(); - // Signal to the profiler that the frame is finished. - profiler.end_frame().unwrap(); - // Query for oldest finished frame (this is almost certainly not the one we just submitted!) and display results in the command line. - if let Some(results) = profiler.process_finished_frame(queue.get_timestamp_period()) - { - latest_profiler_results = Some(results); - } - console_output(&latest_profiler_results, device.features()); - } - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => { - *control_flow = ControlFlow::Exit; + // Signal to the profiler that the frame is finished. + profiler.end_frame().unwrap(); + // Query for oldest finished frame (this is almost certainly not the one we just submitted!) and display results in the command line. + if let Some(results) = + profiler.process_finished_frame(queue.get_timestamp_period()) + { + latest_profiler_results = Some(results); + } + console_output(&latest_profiler_results, device.features()); } - WindowEvent::KeyboardInput { - input: - winit::event::KeyboardInput { - virtual_keycode: Some(keycode), - .. - }, - .. - } => match keycode { - VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, - VirtualKeyCode::Space => { - if let Some(profile_data) = &latest_profiler_results { - wgpu_profiler::chrometrace::write_chrometrace( - std::path::Path::new("trace.json"), - profile_data, - ) - .expect("Failed to write trace.json"); - } + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { + target.exit(); } + WindowEvent::KeyboardInput { + event: + winit::event::KeyEvent { + physical_key: PhysicalKey::Code(keycode), + .. + }, + .. + } => match keycode { + KeyCode::Escape => { + target.exit(); + } + KeyCode::Space => { + if let Some(profile_data) = &latest_profiler_results { + wgpu_profiler::chrometrace::write_chrometrace( + std::path::Path::new("trace.json"), + profile_data, + ) + .expect("Failed to write trace.json"); + } + } + _ => {} + }, _ => {} }, _ => {} - }, - _ => {} - } - }); + }; + }) + .unwrap(); } fn draw( @@ -333,7 +340,7 @@ fn draw( fn main() { tracy_client::Client::start(); //env_logger::init_from_env(env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "warn")); - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = winit::window::WindowBuilder::new() .build(&event_loop) .unwrap();