From 0cebf68306ab0ef08693701532260e1fdc0f1ee9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 9 Feb 2024 13:29:40 +0100 Subject: [PATCH] Introduce a new `ToggleGraphicsProfiler` command (#7607) On macOS, this will enable or disable the Metal HUD at runtime. Note that this only works when Zed is bundled because it requires to set the `MetalHudEnabled` key in the Info.plist. Release Notes: - Added a new `ToggleGraphicsProfiler` command that can be used as an action (or via the `Help -> Toggle Graphics Profiler` menu) to investigate graphics performance. --- crates/gpui/src/platform.rs | 2 +- crates/gpui/src/platform/linux/window.rs | 4 +++ .../gpui/src/platform/mac/metal_renderer.rs | 27 +++++++++++++++---- crates/gpui/src/platform/mac/window.rs | 6 +++++ crates/gpui/src/platform/test/window.rs | 2 ++ crates/gpui/src/window.rs | 10 +++++++ crates/workspace/src/workspace.rs | 2 ++ crates/zed/resources/info/Permissions.plist | 2 ++ crates/zed/src/app_menus.rs | 4 +++ 9 files changed, 53 insertions(+), 6 deletions(-) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index d3e19d2b6ffe01874214ec8c85f054d80c8859c9..6739fee6fc39ce86c86e86b6292a6e1f6490546b 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -182,8 +182,8 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn on_appearance_changed(&self, callback: Box); fn is_topmost_for_position(&self, position: Point) -> bool; fn draw(&self, scene: &Scene); - fn sprite_atlas(&self) -> Arc; + fn set_graphics_profiler_enabled(&self, enabled: bool); #[cfg(any(test, feature = "test-support"))] fn as_test(&mut self) -> Option<&mut TestWindow> { diff --git a/crates/gpui/src/platform/linux/window.rs b/crates/gpui/src/platform/linux/window.rs index d396c7462826e7b649b9855c963624dce80374ff..e5c346b057de347722a4340d16ae3b3bd2669578 100644 --- a/crates/gpui/src/platform/linux/window.rs +++ b/crates/gpui/src/platform/linux/window.rs @@ -428,4 +428,8 @@ impl PlatformWindow for LinuxWindow { let inner = self.0.inner.lock(); inner.renderer.atlas().clone() } + + fn set_graphics_profiler_enabled(&self, enabled: bool) { + todo!("linux") + } } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 166f62ede0ac746e8b8529571cf4dea5aef72234..6b30787b52724a005fef23bb282a49fe42ebc647 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -1,12 +1,12 @@ use crate::{ - point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, - Hsla, MetalAtlas, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, - Quad, ScaledPixels, Scene, Shadow, Size, Surface, Underline, + platform::mac::ns_string, point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, + ContentMask, DevicePixels, Hsla, MetalAtlas, MonochromeSprite, Path, PathId, PathVertex, + PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, Surface, Underline, }; use block::ConcreteBlock; use cocoa::{ - base::{NO, YES}, - foundation::NSUInteger, + base::{nil, NO, YES}, + foundation::{NSDictionary, NSUInteger}, quartzcore::AutoresizingMask, }; use collections::HashMap; @@ -200,6 +200,23 @@ impl MetalRenderer { &self.sprite_atlas } + /// Enables or disables the Metal HUD for debugging purposes. Note that this only works + /// when the app is bundled and it has the `MetalHudEnabled` key set to true in Info.plist. + pub fn set_hud_enabled(&mut self, enabled: bool) { + unsafe { + if enabled { + let hud_properties = NSDictionary::dictionaryWithObject_forKey_( + nil, + ns_string("default"), + ns_string("mode"), + ); + let _: () = msg_send![&*self.layer, setDeveloperHUDProperties: hud_properties]; + } else { + let _: () = msg_send![&*self.layer, setDeveloperHUDProperties: NSDictionary::dictionary(nil)]; + } + } + } + pub fn set_presents_with_transaction(&mut self, presents_with_transaction: bool) { self.presents_with_transaction = presents_with_transaction; self.layer diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index aaa5685895856b0603917cdc5df2d52719d2d3ce..9497c240c333b61bc6b097410504a2a3f28100ae 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -1021,6 +1021,12 @@ impl PlatformWindow for MacWindow { fn sprite_atlas(&self) -> Arc { self.0.lock().renderer.sprite_atlas().clone() } + + /// Enables or disables the Metal HUD for debugging purposes. Note that this only works + /// when the app is bundled and it has the `MetalHudEnabled` key set to true in Info.plist. + fn set_graphics_profiler_enabled(&self, enabled: bool) { + self.0.lock().renderer.set_hud_enabled(enabled); + } } impl HasWindowHandle for MacWindow { diff --git a/crates/gpui/src/platform/test/window.rs b/crates/gpui/src/platform/test/window.rs index c67384a39297adc69b8d7c79880628d256e95772..23e5cdeea7900c8afa39cd0e2f46148475661924 100644 --- a/crates/gpui/src/platform/test/window.rs +++ b/crates/gpui/src/platform/test/window.rs @@ -288,6 +288,8 @@ impl PlatformWindow for TestWindow { self.0.lock().sprite_atlas.clone() } + fn set_graphics_profiler_enabled(&self, _enabled: bool) {} + fn as_test(&mut self) -> Option<&mut TestWindow> { Some(self) } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 8393da1da0ffffdd6e9593c1fdb9e37920b6ff0e..f7f53689f9231cdbc23b50eb74bc74a10c7b4fa9 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -279,6 +279,7 @@ pub struct Window { pub(crate) focus: Option, focus_enabled: bool, pending_input: Option, + graphics_profiler_enabled: bool, } #[derive(Default, Debug)] @@ -462,6 +463,7 @@ impl Window { focus: None, focus_enabled: true, pending_input: None, + graphics_profiler_enabled: false, } } fn new_focus_listener( @@ -1461,6 +1463,14 @@ impl<'a> WindowContext<'a> { } } + /// Toggle the graphics profiler to debug your application's rendering performance. + pub fn toggle_graphics_profiler(&mut self) { + self.window.graphics_profiler_enabled = !self.window.graphics_profiler_enabled; + self.window + .platform_window + .set_graphics_profiler_enabled(self.window.graphics_profiler_enabled); + } + /// Register the given handler to be invoked whenever the global of the given type /// is updated. pub fn observe_global( diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index fc4040be0dcd5f1420515ffe1bb9fbccab8b6355..89adb1e94689e960699e9584669ed0327fbafd80 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -118,6 +118,7 @@ actions!( ToggleRightDock, ToggleBottomDock, CloseAllDocks, + ToggleGraphicsProfiler, ] ); @@ -3395,6 +3396,7 @@ impl Workspace { workspace.reopen_closed_item(cx).detach(); }), ) + .on_action(|_: &ToggleGraphicsProfiler, cx| cx.toggle_graphics_profiler()) } #[cfg(any(test, feature = "test-support"))] diff --git a/crates/zed/resources/info/Permissions.plist b/crates/zed/resources/info/Permissions.plist index bded5a82e2c81d811b8186dde97736170a74b425..fd608afaa0c3252e1dba3529fb67e839d93e4280 100644 --- a/crates/zed/resources/info/Permissions.plist +++ b/crates/zed/resources/info/Permissions.plist @@ -22,3 +22,5 @@ An application in Zed wants to use speech recognition. NSRemindersUsageDescription An application in Zed wants to use your reminders. +MetalHudEnabled + diff --git a/crates/zed/src/app_menus.rs b/crates/zed/src/app_menus.rs index 40d20d61ef309e5f0ad4dd82012b5c60c2cd83cb..a3f214582757c0433b25fe03b9f7b9c993baf1c0 100644 --- a/crates/zed/src/app_menus.rs +++ b/crates/zed/src/app_menus.rs @@ -155,6 +155,10 @@ pub fn app_menus() -> Vec> { MenuItem::action("View Telemetry", crate::OpenTelemetryLog), MenuItem::action("View Dependency Licenses", crate::OpenLicenses), MenuItem::action("Show Welcome", workspace::Welcome), + MenuItem::action( + "Toggle Graphics Profiler", + workspace::ToggleGraphicsProfiler, + ), MenuItem::separator(), MenuItem::separator(), MenuItem::action(