From bdf1d4edea065cb2a82f8bdcb415a68de537e6d4 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 23 Jul 2024 09:56:45 -0600 Subject: [PATCH] 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. --- Cargo.lock | 27 +++++++------------ Cargo.toml | 6 ++--- crates/feedback/src/system_specs.rs | 21 +++++++++++++-- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/gpui.rs | 13 +++++++++ crates/gpui/src/platform.rs | 5 ++-- .../gpui/src/platform/blade/blade_renderer.rs | 18 ++++++++++--- .../gpui/src/platform/linux/wayland/window.rs | 6 ++++- crates/gpui/src/platform/linux/x11/window.rs | 10 ++++--- crates/gpui/src/platform/mac/window.rs | 4 +++ crates/gpui/src/platform/test/window.rs | 10 ++++--- crates/gpui/src/platform/windows/window.rs | 4 +++ crates/gpui/src/window.rs | 8 +++++- crates/media/Cargo.toml | 2 +- crates/zed/src/zed.rs | 24 +++++++++++++++++ docs/src/linux.md | 24 ++++++++++------- 16 files changed, 136 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2000a385e..4b87d30658 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1651,7 +1651,7 @@ dependencies = [ [[package]] name = "blade-graphics" version = "0.4.0" -source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818" +source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" dependencies = [ "ash", "ash-window", @@ -1681,7 +1681,7 @@ dependencies = [ [[package]] name = "blade-macros" version = "0.2.1" -source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818" +source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" dependencies = [ "proc-macro2", "quote", @@ -1691,7 +1691,7 @@ dependencies = [ [[package]] name = "blade-util" version = "0.1.0" -source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818" +source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" dependencies = [ "blade-graphics", "bytemuck", @@ -6644,11 +6644,11 @@ dependencies = [ [[package]] name = "metal" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "550b24b0cd4cf923f36bae78eca457b3a10d8a6a14a9c84cb2687b527e6a84af" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", "core-graphics-types", "foreign-types 0.5.0", @@ -6749,8 +6749,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "naga" -version = "0.20.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=425526828f738c95ec50b016c6a761bc00d2fb25#425526828f738c95ec50b016c6a761bc00d2fb25" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09eeccb9b50f4f7839b214aa3e08be467159506a986c18e0702170ccf720a453" dependencies = [ "arrayvec", "bit-set 0.6.0", @@ -7180,16 +7181,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c564ffcb3a..518b51819b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -295,9 +295,9 @@ async-watch = "0.3.1" async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] } base64 = "0.13" bitflags = "2.6.0" -blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" } -blade-macros = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" } -blade-util = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" } +blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" } +blade-macros = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" } +blade-util = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" } cap-std = "3.0" cargo_toml = "0.20" chrono = { version = "0.4", features = ["serde"] } diff --git a/crates/feedback/src/system_specs.rs b/crates/feedback/src/system_specs.rs index e0448867ef..a570180187 100644 --- a/crates/feedback/src/system_specs.rs +++ b/crates/feedback/src/system_specs.rs @@ -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, + gpu_specs: Option, } impl SystemSpecs { - pub fn new(cx: &AppContext) -> Task { + pub fn new(cx: &WindowContext) -> Task { 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::>() .join("\n"); diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 018cd3d723..ad2748eeb6 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -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] diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 29ffed710d..fa75d7ea03 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -341,3 +341,16 @@ impl Flatten for Result { 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, +} diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 75a0c806c4..8fc9405328 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -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; #[cfg(any(test, feature = "test-support"))] fn as_test(&mut self) -> Option<&mut TestWindow> { diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index ee60261846..27e76b9778 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -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() diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index ba97f202fc..c43ec18d08 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -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 { + self.borrow().renderer.gpu_specs().into() + } } fn update_window(mut state: RefMut) { diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index fb077634a9..9e4908627e 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -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 { + self.0.state.borrow().renderer.gpu_specs().into() + } } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index b5ce6719ee..3548911518 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -1096,6 +1096,10 @@ impl PlatformWindow for MacWindow { fn sprite_atlas(&self) -> Arc { self.0.lock().renderer.sprite_atlas().clone() } + + fn gpu_specs(&self) -> Option { + None + } } impl rwh::HasWindowHandle for MacWindow { diff --git a/crates/gpui/src/platform/test/window.rs b/crates/gpui/src/platform/test/window.rs index 8c7ee5507a..79a1c04401 100644 --- a/crates/gpui/src/platform/test/window.rs +++ b/crates/gpui/src/platform/test/window.rs @@ -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 { + None + } } pub(crate) struct TestAtlasState { diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 50cdf063e2..01a71f70e0 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -654,6 +654,10 @@ impl PlatformWindow for WindowsWindow { fn get_raw_handle(&self) -> HWND { self.0.hwnd } + + fn gpu_specs(&self) -> Option { + Some(self.0.state.borrow().renderer.gpu_specs()) + } } #[implement(IDropTarget)] diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index c5bada903e..4b2ebcbda1 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -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 { + self.window.platform_window.gpu_specs() + } } #[cfg(target_os = "windows")] diff --git a/crates/media/Cargo.toml b/crates/media/Cargo.toml index ac22eccde6..de26ac1203 100644 --- a/crates/media/Cargo.toml +++ b/crates/media/Cargo.toml @@ -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] diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 23573d4588..7cdfbaeda0 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -139,6 +139,30 @@ pub fn initialize_workspace(app_state: Arc, 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) }); diff --git a/docs/src/linux.md b/docs/src/linux.md index 27aaa95130..537815d188 100644 --- a/docs/src/linux.md +++ b/docs/src/linux.md @@ -12,11 +12,14 @@ We also offer a preview build of Zed which receives updates about a week ahead o curl -f https://zed.dev/install.sh | ZED_CHANNEL=preview sh ``` -The install script does not work on systems that: -* have no system-wide glibc (for example on NixOS or Alpine) +The Zed installed by the script does not work on systems that: +* have no Vulkan compatible GPU available (for example Linux on an M-series macBook) +* have no system-wide glibc (for example on NixOS or Alpine by default) * have a glibc older than version 2.29 (for example Amazon Linux 2 or Ubuntu 18 and earlier) * use an architecture other than 64-bit Intel or 64-bit ARM (for example a 32-bit or RISC-V machine) +Both Nix and Alpine have third-party Zed packages available (though they are currently a few weeks out of date). If you'd like to use our builds they do work if you install a glibc compatibility layer. On NixOS you can try [nix-ld](https://github.com/Mic92/nix-ld), and on Alpine [gcompat](https://wiki.alpinelinux.org/wiki/Running_glibc_programs). + ## Other ways to install Zed on Linux Zed is open source, and [you can install from source](./development/linux.md). @@ -80,30 +83,31 @@ Linux works on a large variety of systems configured in many different ways. We If you see an error like "/lib64/libc.so.6: version 'GLIBC_2.29' not found" it means that your distribution's version of glibc is too old. You can either upgrade your system, or [install Zed from source](./development/linux.md). ### Zed fails to open windows +### Zed is very slow Zed requires a GPU to run effectively. Under the hood, we use [Vulkan](https://www.vulkan.org/) to communicate with your GPU. If you are seeing problems with performance, or Zed fails to load, it is possible that Vulkan is the culprit. If you're using an AMD GPU, you might get a 'Broken Pipe' error. Try using the RADV or Mesa drivers. (See the following GitHub issue for more details: [#13880](https://github.com/zed-industries/zed/issues/13880)). -Otherwise, if you see error messages like: "Zed failed to open a window: NoSupportedDeviceFound" or "called `Result::unwrap()` on an `Err` value: ERROR_INITIALIZATION_FAILED", you can begin troubleshooting Vulkan, by installing the `vulkan-tools` package, and running: +If you see a notification saying `Zed failed to open a window: NoSupportedDeviceFound` this means that Vulkan cannot find a compatible GPU. You can begin troubleshooting Vulkan by installing the `vulkan-tools` package and running: ```sh vkcube ``` -This should output a line describing your current graphics setup. If it contains `llvmpipe` then Vulkan is not using a GPU, which will make Zed run very slowly. +This should output a line describing your current graphics setup and show a rotating cube. If this does not work, you should be able to fix it by installing Vulkan compatible GPU drivers, however in some cases (for example running Linux on an Arm-based MacBook) there is no Vulkan support yet. -In most cases this can be fixed by configuring Vulkan and installing compatible GPU drivers, however in some cases (for example running Linux on an Arm-based MacBook) there is no Vulkan support yet. +If you see errors like `ERROR_INITIALIZATION_FAILED` or `GPU Crashed` or `ERROR_SURFACE_LOST_KHR` then you may be able to work around this by installing different drivers for your GPU, or by selecting a different GPU to run on. (See the following GitHub issue for more details: [#14225](https://github.com/zed-industries/zed/issues/14225)) -For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good steps. +As of Zed v0.146.x we log the selected GPU driver and you should see `Using GPU: ...` in the Zed log (`~/.local/share/zed/logs/Zed.log`). -### Zed is very slow +If Zed is selecting your integrated GPU instead of your discrete GPU, you can fix this by exporting the environment variable `DRI_PRIME=1` before running Zed. -If you're on relatively modern hardware Zed should feel fast to use. That said, we do rely on the GPU to make rendering quick. +If you are using Mesa, and want more control over which GPU is selected you can run `MESA_VK_DEVICE_SELECT=list zed --foreground` to get a list of available GPUs and then export `MESA_VK_DEVICE_SELECT=xxxx:yyyy` to choose a specific device. -If you install the `vulkan-tools` package and run `vkcube` and you see `llvmpipe` in the output, you need to make sure your GPU is configured correctly. +If you are using `amdvlk` you may find that zed only opens when run with `sudo $(which zed)`. To fix this, remove the `amdvlk` and `lib32-amdvlk` packages and install mesa/vulkan instead. ([#14141](https://github.com/zed-industries/zed/issues/14141). -For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good troubleshooting steps. +For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good steps that translate well to most distributions. If Vulkan is configured correctly, and Zed is still slow for you, please [file an issue](https://github.com/zed-industries/zed) with as much information as possible.