From d2a4af35af688fd1a037b588b29a74aebc087c3f Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 3 Jul 2021 01:50:57 -0400 Subject: [PATCH] Generation of memory reports for Hubs --- wgpu-core/src/hub.rs | 131 ++++++++++++++++++++++++++++++++++++- wgpu/examples/framework.rs | 12 ++++ wgpu/src/backend/direct.rs | 4 ++ wgpu/src/lib.rs | 6 ++ 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index bfaa0f2145..1e676e3c9d 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -15,7 +15,7 @@ use wgt::Backend; #[cfg(debug_assertions)] use std::cell::Cell; -use std::{fmt::Debug, marker::PhantomData, ops}; +use std::{fmt::Debug, marker::PhantomData, mem, ops}; /// A simple structure to manage identities of objects. #[derive(Debug)] @@ -73,6 +73,20 @@ enum Element { Error(Epoch, String), } +#[derive(Clone, Debug, Default)] +pub struct StorageReport { + pub num_occupied: usize, + pub num_vacant: usize, + pub num_error: usize, + pub element_size: usize, +} + +impl StorageReport { + pub fn is_empty(&self) -> bool { + self.num_occupied + self.num_vacant + self.num_error == 0 + } +} + #[derive(Clone, Debug)] pub(crate) struct InvalidId; @@ -212,6 +226,21 @@ impl Storage { _ => None, }) } + + fn generate_report(&self) -> StorageReport { + let mut report = StorageReport { + element_size: mem::size_of::(), + ..Default::default() + }; + for element in self.map.iter() { + match *element { + Element::Occupied(..) => report.num_occupied += 1, + Element::Vacant => report.num_vacant += 1, + Element::Error(..) => report.num_error += 1, + } + } + report + } } /// Type system for enforcing the lock order on shared HUB structures. @@ -526,6 +555,32 @@ impl> Registry< } } +#[derive(Debug)] +pub struct HubReport { + pub adapters: StorageReport, + pub devices: StorageReport, + pub swap_chains: StorageReport, + pub pipeline_layouts: StorageReport, + pub shader_modules: StorageReport, + pub bind_group_layouts: StorageReport, + pub bind_groups: StorageReport, + pub command_buffers: StorageReport, + pub render_bundles: StorageReport, + pub render_pipelines: StorageReport, + pub compute_pipelines: StorageReport, + pub query_sets: StorageReport, + pub buffers: StorageReport, + pub textures: StorageReport, + pub texture_views: StorageReport, + pub samplers: StorageReport, +} + +impl HubReport { + pub fn is_empty(&self) -> bool { + self.adapters.is_empty() + } +} + pub struct Hub { pub adapters: Registry, id::AdapterId, F>, pub devices: Registry, id::DeviceId, F>, @@ -566,9 +621,7 @@ impl Hub { samplers: Registry::new(A::VARIANT, factory), } } -} -impl Hub { //TODO: instead of having a hacky `with_adapters` parameter, // we should have `clear_device(device_id)` that specifically destroys // everything related to a logical device. @@ -711,6 +764,27 @@ impl Hub { self.adapters.data.write().map.clear(); } } + + pub fn generate_report(&self) -> HubReport { + HubReport { + adapters: self.adapters.data.read().generate_report(), + devices: self.devices.data.read().generate_report(), + swap_chains: self.swap_chains.data.read().generate_report(), + pipeline_layouts: self.pipeline_layouts.data.read().generate_report(), + shader_modules: self.shader_modules.data.read().generate_report(), + bind_group_layouts: self.bind_group_layouts.data.read().generate_report(), + bind_groups: self.bind_groups.data.read().generate_report(), + command_buffers: self.command_buffers.data.read().generate_report(), + render_bundles: self.render_bundles.data.read().generate_report(), + render_pipelines: self.render_pipelines.data.read().generate_report(), + compute_pipelines: self.compute_pipelines.data.read().generate_report(), + query_sets: self.query_sets.data.read().generate_report(), + buffers: self.buffers.data.read().generate_report(), + textures: self.textures.data.read().generate_report(), + texture_views: self.texture_views.data.read().generate_report(), + samplers: self.samplers.data.read().generate_report(), + } + } } pub struct Hubs { @@ -743,6 +817,21 @@ impl Hubs { } } +#[derive(Debug)] +pub struct GlobalReport { + pub surfaces: StorageReport, + #[cfg(vulkan)] + pub vulkan: Option, + #[cfg(metal)] + pub metal: Option, + #[cfg(dx12)] + pub dx12: Option, + #[cfg(dx11)] + pub dx11: Option, + #[cfg(gl)] + pub gl: Option, +} + pub struct Global { pub instance: Instance, pub surfaces: Registry, @@ -765,6 +854,42 @@ impl Global { // this is used for tests, which keep the adapter hub.clear(&mut *surface_guard, false); } + + pub fn generate_report(&self) -> GlobalReport { + GlobalReport { + surfaces: self.surfaces.data.read().generate_report(), + #[cfg(vulkan)] + vulkan: if self.instance.vulkan.is_some() { + Some(self.hubs.vulkan.generate_report()) + } else { + None + }, + #[cfg(metal)] + metal: if self.instance.metal.is_some() { + Some(self.hubs.metal.generate_report()) + } else { + None + }, + #[cfg(dx12)] + dx12: if self.instance.dx12.is_some() { + Some(self.hubs.dx12.generate_report()) + } else { + None + }, + #[cfg(dx11)] + dx11: if self.instance.dx11.is_some() { + Some(self.hubs.dx11.generate_report()) + } else { + None + }, + #[cfg(gl)] + gl: if self.instance.gl.is_some() { + Some(self.hubs.gl.generate_report()) + } else { + None + }, + } + } } impl Drop for Global { diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 52d7ddd76f..2dc88baec8 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -254,6 +254,18 @@ fn start( | WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } + #[cfg(not(target_arch = "wasm32"))] + WindowEvent::KeyboardInput { + input: + event::KeyboardInput { + virtual_keycode: Some(event::VirtualKeyCode::R), + state: event::ElementState::Pressed, + .. + }, + .. + } => { + println!("{:#?}", instance.generate_report()); + } _ => { example.update(event); } diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 58a9b3f2a9..5233bffc3d 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -50,6 +50,10 @@ impl Context { })) } + pub fn generate_report(&self) -> wgc::hub::GlobalReport { + self.0.generate_report() + } + /*TODO: raw surface #[cfg(any(target_os = "ios", target_os = "macos"))] pub unsafe fn create_surface_from_core_animation_layer( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 72bcb29c0c..86db2e04e6 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1454,6 +1454,12 @@ impl Instance { pub fn poll_all(&self, force_wait: bool) { self.context.instance_poll_all_devices(force_wait); } + + /// Generates memory report. + #[cfg(not(target_arch = "wasm32"))] + pub fn generate_report(&self) -> wgc::hub::GlobalReport { + self.context.generate_report() + } } impl Adapter {