linux: Better GPU debugging (#14706)
Release Notes: - linux: Added GPU information to `editor: Copy System Specs to Clipboard` - linux: Show a prominant warning before running under llvmpipe and similar.
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use client::telemetry;
|
||||
use gpui::{AppContext, Task};
|
||||
use gpui::Task;
|
||||
use human_bytes::human_bytes;
|
||||
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
|
||||
use serde::Serialize;
|
||||
use std::{env, fmt::Display};
|
||||
use sysinfo::{MemoryRefreshKind, RefreshKind, System};
|
||||
use ui::WindowContext;
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct SystemSpecs {
|
||||
@@ -15,10 +16,11 @@ pub struct SystemSpecs {
|
||||
memory: u64,
|
||||
architecture: &'static str,
|
||||
commit_sha: Option<String>,
|
||||
gpu_specs: Option<String>,
|
||||
}
|
||||
|
||||
impl SystemSpecs {
|
||||
pub fn new(cx: &AppContext) -> Task<Self> {
|
||||
pub fn new(cx: &WindowContext) -> Task<Self> {
|
||||
let app_version = AppVersion::global(cx).to_string();
|
||||
let release_channel = ReleaseChannel::global(cx);
|
||||
let os_name = telemetry::os_name();
|
||||
@@ -34,6 +36,15 @@ impl SystemSpecs {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let gpu_specs = if let Some(specs) = cx.gpu_specs() {
|
||||
Some(format!(
|
||||
"{} || {} || {}",
|
||||
specs.device_name, specs.driver_name, specs.driver_info
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
let os_version = telemetry::os_version();
|
||||
SystemSpecs {
|
||||
@@ -44,6 +55,7 @@ impl SystemSpecs {
|
||||
memory,
|
||||
architecture,
|
||||
commit_sha,
|
||||
gpu_specs,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -67,6 +79,11 @@ impl Display for SystemSpecs {
|
||||
format!("Architecture: {}", self.architecture),
|
||||
]
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.gpu_specs
|
||||
.as_ref()
|
||||
.map(|specs| format!("GPU: {}", specs)),
|
||||
)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ core-text = "20.1"
|
||||
foreign-types = "0.5"
|
||||
log.workspace = true
|
||||
media.workspace = true
|
||||
metal = "0.25"
|
||||
metal = "0.29"
|
||||
objc = "0.2"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
|
||||
@@ -341,3 +341,16 @@ impl<T> Flatten<T> for Result<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
/// Information about the GPU GPUI is running on
|
||||
pub struct GPUSpecs {
|
||||
/// true if the GPU is really a fake (like llvmpipe) running on the CPU
|
||||
pub is_software_emulated: bool,
|
||||
/// Name of the device as reported by vulkan
|
||||
pub device_name: String,
|
||||
/// Name of the driver as reported by vulkan
|
||||
pub driver_name: String,
|
||||
/// Further driver info as reported by vulkan
|
||||
pub driver_info: String,
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ mod windows;
|
||||
|
||||
use crate::{
|
||||
point, Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels,
|
||||
DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GlyphId, Keymap,
|
||||
LineLayout, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams,
|
||||
DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GPUSpecs, GlyphId,
|
||||
Keymap, LineLayout, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, Scene, SharedString, Size, Task, TaskLabel, WindowContext,
|
||||
DEFAULT_WINDOW_SIZE,
|
||||
};
|
||||
@@ -366,6 +366,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
|
||||
}
|
||||
}
|
||||
fn set_client_inset(&self, _inset: Pixels) {}
|
||||
fn gpu_specs(&self) -> Option<GPUSpecs>;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn as_test(&mut self) -> Option<&mut TestWindow> {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
use super::{BladeAtlas, PATH_TEXTURE_FORMAT};
|
||||
use crate::{
|
||||
AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, Hsla, MonochromeSprite, Path,
|
||||
PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size,
|
||||
Underline,
|
||||
AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, GPUSpecs, Hsla,
|
||||
MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad,
|
||||
ScaledPixels, Scene, Shadow, Size, Underline,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use collections::HashMap;
|
||||
@@ -451,6 +451,18 @@ impl BladeRenderer {
|
||||
&self.atlas
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "macos", allow(dead_code))]
|
||||
pub fn gpu_specs(&self) -> GPUSpecs {
|
||||
let info = self.gpu.device_information();
|
||||
|
||||
GPUSpecs {
|
||||
is_software_emulated: info.is_software_emulated,
|
||||
device_name: info.device_name.clone(),
|
||||
driver_name: info.driver_name.clone(),
|
||||
driver_info: info.driver_info.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn layer(&self) -> metal::MetalLayer {
|
||||
self.gpu.metal_layer().unwrap()
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::platform::linux::wayland::serial::SerialKind;
|
||||
use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
|
||||
use crate::scene::Scene;
|
||||
use crate::{
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, Globals, Modifiers, Output, Pixels,
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, GPUSpecs, Globals, Modifiers, Output, Pixels,
|
||||
PlatformDisplay, PlatformInput, Point, PromptLevel, ResizeEdge, Size, Tiling,
|
||||
WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
|
||||
WindowControls, WindowDecorations, WindowParams,
|
||||
@@ -1007,6 +1007,10 @@ impl PlatformWindow for WaylandWindow {
|
||||
update_window(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GPUSpecs> {
|
||||
self.borrow().renderer.gpu_specs().into()
|
||||
}
|
||||
}
|
||||
|
||||
fn update_window(mut state: RefMut<WaylandWindowState>) {
|
||||
|
||||
@@ -2,9 +2,9 @@ use anyhow::Context;
|
||||
|
||||
use crate::{
|
||||
platform::blade::{BladeRenderer, BladeSurfaceConfig},
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, Modifiers,
|
||||
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
|
||||
Point, PromptLevel, ResizeEdge, Scene, Size, Tiling, WindowAppearance,
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GPUSpecs,
|
||||
Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
|
||||
PlatformWindow, Point, PromptLevel, ResizeEdge, Scene, Size, Tiling, WindowAppearance,
|
||||
WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowParams,
|
||||
X11ClientStatePtr,
|
||||
};
|
||||
@@ -1385,4 +1385,8 @@ impl PlatformWindow for X11Window {
|
||||
appearance_changed();
|
||||
}
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GPUSpecs> {
|
||||
self.0.state.borrow().renderer.gpu_specs().into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,6 +1096,10 @@ impl PlatformWindow for MacWindow {
|
||||
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.lock().renderer.sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<crate::GPUSpecs> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl rwh::HasWindowHandle for MacWindow {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, Pixels,
|
||||
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
|
||||
Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
|
||||
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, GPUSpecs,
|
||||
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
|
||||
Point, Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
|
||||
WindowParams,
|
||||
};
|
||||
use collections::HashMap;
|
||||
@@ -273,6 +273,10 @@ impl PlatformWindow for TestWindow {
|
||||
fn start_window_move(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GPUSpecs> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TestAtlasState {
|
||||
|
||||
@@ -654,6 +654,10 @@ impl PlatformWindow for WindowsWindow {
|
||||
fn get_raw_handle(&self) -> HWND {
|
||||
self.0.hwnd
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GPUSpecs> {
|
||||
Some(self.0.state.borrow().renderer.gpu_specs())
|
||||
}
|
||||
}
|
||||
|
||||
#[implement(IDropTarget)]
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
AnyView, AppContext, Arena, Asset, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow,
|
||||
Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener,
|
||||
DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
|
||||
FileDropEvent, Flatten, FontId, Global, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
FileDropEvent, Flatten, FontId, GPUSpecs, Global, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,
|
||||
KeystrokeEvent, LayoutId, LineLayoutIndex, Model, ModelContext, Modifiers,
|
||||
ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent,
|
||||
@@ -3733,6 +3733,12 @@ impl<'a> WindowContext<'a> {
|
||||
.dispatch_tree
|
||||
.on_action(action_type, Rc::new(listener));
|
||||
}
|
||||
|
||||
/// Read information about the GPU backing this window.
|
||||
/// Currently returns None on Mac and Windows.
|
||||
pub fn gpu_specs(&self) -> Option<GPUSpecs> {
|
||||
self.window.platform_window.gpu_specs()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
|
||||
@@ -18,7 +18,7 @@ anyhow.workspace = true
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation.workspace = true
|
||||
foreign-types = "0.5"
|
||||
metal = "0.25"
|
||||
metal = "0.29"
|
||||
objc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -139,6 +139,30 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
})
|
||||
.detach();
|
||||
|
||||
if let Some(specs) = cx.gpu_specs() {
|
||||
log::info!("Using GPU: {:?}", specs);
|
||||
if specs.is_software_emulated && std::env::var("ZED_ALLOW_EMULATED_GPU").is_err() {
|
||||
let message = format!(db::indoc!{r#"
|
||||
Zed uses Vulkan for rendering and requires a compatible GPU.
|
||||
|
||||
Currently you are using a software emulated GPU ({}) which
|
||||
will result in awful performance.
|
||||
|
||||
For troubleshooting see: https://zed.dev/docs/linux
|
||||
"#}, specs.device_name);
|
||||
let prompt = cx.prompt(PromptLevel::Critical, "Unsupported GPU", Some(&message),
|
||||
&["Troubleshoot and Quit"]);
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if prompt.await == Ok(0) {
|
||||
cx.update(|cx| {
|
||||
cx.open_url("https://zed.dev/docs/linux#zed-fails-to-open-windows");
|
||||
cx.quit();
|
||||
}).ok();
|
||||
}
|
||||
}).detach()
|
||||
}
|
||||
}
|
||||
|
||||
let inline_completion_button = cx.new_view(|cx| {
|
||||
inline_completion_button::InlineCompletionButton::new(app_state.fs.clone(), cx)
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user