diff --git a/desktop/src/app.rs b/desktop/src/app.rs index 2a4839c7c78e..f4e1f4643128 100644 --- a/desktop/src/app.rs +++ b/desktop/src/app.rs @@ -3,8 +3,8 @@ use crate::custom_event::RuffleEvent; use crate::gui::{GuiController, MENU_HEIGHT}; use crate::player::{PlayerController, PlayerOptions}; use crate::util::{ - get_screen_size, parse_url, pick_file, winit_key_to_char, winit_to_ruffle_key_code, - winit_to_ruffle_text_control, + get_screen_size, parse_url, pick_file, plot_stats_in_tracy, winit_key_to_char, + winit_to_ruffle_key_code, winit_to_ruffle_text_control, }; use anyhow::{Context, Error}; use ruffle_core::{PlayerEvent, StageDisplayState}; @@ -136,10 +136,7 @@ impl App { } else { self.gui.borrow_mut().render(None); } - #[cfg(feature = "tracy")] - tracing_tracy::client::Client::running() - .expect("tracy client must be running") - .frame_mark(); + plot_stats_in_tracy(&self.gui.borrow().descriptors().wgpu_instance); } } diff --git a/desktop/src/gui/controller.rs b/desktop/src/gui/controller.rs index 382961961f65..b87784ead49f 100644 --- a/desktop/src/gui/controller.rs +++ b/desktop/src/gui/controller.rs @@ -58,7 +58,7 @@ impl GuiController { let surface = unsafe { instance.create_surface(window.as_ref()) }?; let (adapter, device, queue) = futures::executor::block_on(request_adapter_and_device( backend, - instance, + &instance, Some(&surface), opt.power.into(), opt.trace_path(), @@ -83,7 +83,7 @@ impl GuiController { view_formats: Default::default(), }, ); - let descriptors = Descriptors::new(adapter, device, queue); + let descriptors = Descriptors::new(instance, adapter, device, queue); let egui_ctx = Context::default(); if let Some(Theme::Light) = window.theme() { egui_ctx.set_visuals(egui::Visuals::light()); diff --git a/desktop/src/util.rs b/desktop/src/util.rs index e11211bc41b7..b553925a9233 100644 --- a/desktop/src/util.rs +++ b/desktop/src/util.rs @@ -342,3 +342,42 @@ pub fn pick_file(in_ui: bool, path: Option) -> Option { pub fn pick_file(_in_ui: bool, path: Option) -> Option { actually_pick_file(path) } + +#[cfg(not(feature = "tracy"))] +pub fn plot_stats_in_tracy(_instance: &wgpu::Instance) {} + +#[cfg(feature = "tracy")] +pub fn plot_stats_in_tracy(instance: &wgpu::Instance) { + use tracing_tracy::client::*; + const BIND_GROUPS: PlotName = plot_name!("Bind Groups"); + const BUFFERS: PlotName = plot_name!("Buffers"); + const TEXTURES: PlotName = plot_name!("Textures"); + const TEXTURE_VIEWS: PlotName = plot_name!("Texture Views"); + + let tracy = Client::running().expect("tracy client must be running"); + let report = instance.generate_report(); + + #[allow(unused_mut)] + let mut backend = None; + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + { + backend = backend.or(report.vulkan).or(report.gl); + } + #[cfg(windows)] + { + backend = backend.or(report.dx12).or(report.dx11); + } + #[cfg(any(target_os = "macos", target_os = "ios"))] + { + backend = backend.or(report.metal); + } + + if let Some(stats) = backend { + tracy.plot(BIND_GROUPS, stats.bind_groups.num_occupied as f64); + tracy.plot(BUFFERS, stats.buffers.num_occupied as f64); + tracy.plot(TEXTURES, stats.textures.num_occupied as f64); + tracy.plot(TEXTURE_VIEWS, stats.texture_views.num_occupied as f64); + } + + tracy.frame_mark(); +} diff --git a/exporter/src/main.rs b/exporter/src/main.rs index e2dee7de4755..cd63dc326420 100644 --- a/exporter/src/main.rs +++ b/exporter/src/main.rs @@ -407,14 +407,14 @@ fn main() -> Result<()> { }); let (adapter, device, queue) = futures::executor::block_on(request_adapter_and_device( opt.graphics.into(), - instance, + &instance, None, opt.power.into(), trace_path(&opt), )) .map_err(|e| anyhow!(e.to_string()))?; - let descriptors = Arc::new(Descriptors::new(adapter, device, queue)); + let descriptors = Arc::new(Descriptors::new(instance, adapter, device, queue)); if opt.swf.is_file() { capture_single_swf(descriptors, &opt)?; diff --git a/render/wgpu/src/backend.rs b/render/wgpu/src/backend.rs index d2070538eb1a..305168c0825e 100644 --- a/render/wgpu/src/backend.rs +++ b/render/wgpu/src/backend.rs @@ -67,13 +67,13 @@ impl WgpuRenderBackend { let surface = instance.create_surface_from_canvas(canvas)?; let (adapter, device, queue) = request_adapter_and_device( wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL, - instance, + &instance, Some(&surface), wgpu::PowerPreference::HighPerformance, None, ) .await?; - let descriptors = Descriptors::new(adapter, device, queue); + let descriptors = Descriptors::new(instance, adapter, device, queue); let target = SwapChainTarget::new(surface, &descriptors.adapter, (1, 1), &descriptors.device); Self::new(Arc::new(descriptors), target) @@ -102,12 +102,12 @@ impl WgpuRenderBackend { let surface = unsafe { instance.create_surface(window) }?; let (adapter, device, queue) = futures::executor::block_on(request_adapter_and_device( backend, - instance, + &instance, Some(&surface), power_preference, trace_path, ))?; - let descriptors = Descriptors::new(adapter, device, queue); + let descriptors = Descriptors::new(instance, adapter, device, queue); let target = SwapChainTarget::new(surface, &descriptors.adapter, size, &descriptors.device); Self::new(Arc::new(descriptors), target) } @@ -133,12 +133,12 @@ impl WgpuRenderBackend { }); let (adapter, device, queue) = futures::executor::block_on(request_adapter_and_device( backend, - instance, + &instance, None, power_preference, trace_path, ))?; - let descriptors = Descriptors::new(adapter, device, queue); + let descriptors = Descriptors::new(instance, adapter, device, queue); let target = crate::target::TextureTarget::new(&descriptors.device, size)?; Self::new(Arc::new(descriptors), target) } @@ -1031,7 +1031,7 @@ impl RenderBackend for WgpuRenderBackend { pub async fn request_adapter_and_device( backend: wgpu::Backends, - instance: wgpu::Instance, + instance: &wgpu::Instance, surface: Option<&wgpu::Surface>, power_preference: wgpu::PowerPreference, trace_path: Option<&Path>, diff --git a/render/wgpu/src/descriptors.rs b/render/wgpu/src/descriptors.rs index 37ae26d1ff69..23a64f3dad77 100644 --- a/render/wgpu/src/descriptors.rs +++ b/render/wgpu/src/descriptors.rs @@ -12,6 +12,7 @@ use std::mem; use std::sync::{Arc, Mutex}; pub struct Descriptors { + pub wgpu_instance: wgpu::Instance, pub adapter: wgpu::Adapter, pub device: wgpu::Device, pub limits: wgpu::Limits, @@ -34,7 +35,12 @@ impl Debug for Descriptors { } impl Descriptors { - pub fn new(adapter: wgpu::Adapter, device: wgpu::Device, queue: wgpu::Queue) -> Self { + pub fn new( + instance: wgpu::Instance, + adapter: wgpu::Adapter, + device: wgpu::Device, + queue: wgpu::Queue, + ) -> Self { let limits = device.limits(); let bind_layouts = BindLayouts::new(&device); let bitmap_samplers = BitmapSamplers::new(&device); @@ -57,6 +63,7 @@ impl Descriptors { let filters = Filters::new(&device); Self { + wgpu_instance: instance, adapter, device, limits, diff --git a/tests/tests/util/environment.rs b/tests/tests/util/environment.rs index 09945f951422..ca43b6f953fd 100644 --- a/tests/tests/util/environment.rs +++ b/tests/tests/util/environment.rs @@ -15,20 +15,22 @@ use std::sync::{Arc, OnceLock}; but for `cargo nextest run` it's a big cost per test if it's not going to use it. */ -fn create_wgpu_device() -> Option<(wgpu::Adapter, wgpu::Device, wgpu::Queue)> { +fn create_wgpu_device() -> Option<(wgpu::Instance, wgpu::Adapter, wgpu::Device, wgpu::Queue)> { + let instance = wgpu::Instance::new(Default::default()); futures::executor::block_on(request_adapter_and_device( wgpu::Backends::all(), - wgpu::Instance::new(Default::default()), + &instance, None, Default::default(), None, )) .ok() + .map(|(adapter, device, queue)| (instance, adapter, device, queue)) } fn build_wgpu_descriptors() -> Option> { - if let Some((adapter, device, queue)) = create_wgpu_device() { - Some(Arc::new(Descriptors::new(adapter, device, queue))) + if let Some((instance, adapter, device, queue)) = create_wgpu_device() { + Some(Arc::new(Descriptors::new(instance, adapter, device, queue))) } else { None }