Compare commits

...

3 Commits

Author SHA1 Message Date
Thorsten Ball
3ab1475f26 Fix Clippy 2024-07-18 16:22:03 +02:00
Thorsten Ball
aef9751e05 Renaming setting 2024-07-18 16:08:23 +02:00
Thorsten Ball
c68c8928c2 gpui/zed: Allow setting a GPU preference
This adds a new setting:

```jsonc
{
  "gpu": "discrete" // or: "integrated
}
```

On macOS, this setting will have an effect when selecting the device
with which to render windows.

On Linux, it's without an effect.
2024-07-18 16:04:53 +02:00
11 changed files with 98 additions and 12 deletions

1
Cargo.lock generated
View File

@@ -13699,6 +13699,7 @@ dependencies = [
"release_channel", "release_channel",
"repl", "repl",
"rope", "rope",
"schemars",
"search", "search",
"serde", "serde",
"serde_json", "serde_json",

View File

@@ -67,5 +67,6 @@ fn notification_window_options(
app_id: Some(app_id.to_owned()), app_id: Some(app_id.to_owned()),
window_min_size: None, window_min_size: None,
window_decorations: Some(WindowDecorations::Client), window_decorations: Some(WindowDecorations::Client),
gpu: None,
} }
} }

View File

@@ -58,6 +58,7 @@ fn build_window_options(display_id: DisplayId, bounds: Bounds<Pixels>) -> Window
app_id: None, app_id: None,
window_min_size: None, window_min_size: None,
window_decorations: None, window_decorations: None,
gpu: None,
} }
} }

View File

@@ -252,6 +252,16 @@ pub enum Decorations {
}, },
} }
/// A type to describe which GPU to prefer.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
pub enum Gpu {
/// The window is rendered using the integrated (lower-power) GPU
#[default]
Integrated,
/// The window is rendered using the discrete GPU
Discrete,
}
/// What window controls this platform supports /// What window controls this platform supports
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
pub struct WindowControls { pub struct WindowControls {
@@ -679,6 +689,10 @@ pub struct WindowOptions {
/// Whether to use client or server side decorations. Wayland only /// Whether to use client or server side decorations. Wayland only
/// Note that this may be ignored. /// Note that this may be ignored.
pub window_decorations: Option<WindowDecorations>, pub window_decorations: Option<WindowDecorations>,
/// Whether to prefer one GPU over another. macOS only
/// Note that this may be ignored.
pub gpu: Option<Gpu>,
} }
/// The variables that can be configured when creating a new window /// The variables that can be configured when creating a new window
@@ -707,6 +721,11 @@ pub(crate) struct WindowParams {
#[cfg_attr(target_os = "linux", allow(dead_code))] #[cfg_attr(target_os = "linux", allow(dead_code))]
pub window_min_size: Option<Size<Pixels>>, pub window_min_size: Option<Size<Pixels>>,
/// Whether to prefer one GPU over another. macOS only
/// Note that this may be ignored.
#[cfg_attr(target_os = "linux", allow(dead_code))]
pub gpu: Option<Gpu>,
} }
/// Represents the status of how a window should be opened. /// Represents the status of how a window should be opened.
@@ -757,6 +776,7 @@ impl Default for WindowOptions {
app_id: None, app_id: None,
window_min_size: None, window_min_size: None,
window_decorations: None, window_decorations: None,
gpu: None,
} }
} }
} }

View File

@@ -3,9 +3,9 @@
use super::{BladeAtlas, PATH_TEXTURE_FORMAT}; use super::{BladeAtlas, PATH_TEXTURE_FORMAT};
use crate::{ use crate::{
AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, Hsla, MonochromeSprite, Path, AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, Gpu, Hsla, MonochromeSprite,
PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow,
Underline, Size, Underline,
}; };
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use collections::HashMap; use collections::HashMap;
@@ -32,6 +32,7 @@ pub unsafe fn new_renderer(
native_view: *mut c_void, native_view: *mut c_void,
bounds: crate::Size<f32>, bounds: crate::Size<f32>,
transparent: bool, transparent: bool,
_gpu: Option<Gpu>,
) -> Renderer { ) -> Renderer {
use raw_window_handle as rwh; use raw_window_handle as rwh;
struct RawWindow { struct RawWindow {

View File

@@ -1,7 +1,7 @@
use super::metal_atlas::MetalAtlas; use super::metal_atlas::MetalAtlas;
use crate::{ use crate::{
point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels,
Hsla, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, Gpu, Hsla, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad,
ScaledPixels, Scene, Shadow, Size, Surface, Underline, ScaledPixels, Scene, Shadow, Size, Surface, Underline,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
@@ -38,8 +38,9 @@ pub unsafe fn new_renderer(
_native_view: *mut c_void, _native_view: *mut c_void,
_bounds: crate::Size<f32>, _bounds: crate::Size<f32>,
_transparent: bool, _transparent: bool,
gpu: Option<Gpu>,
) -> Renderer { ) -> Renderer {
MetalRenderer::new(context) MetalRenderer::new(context, gpu)
} }
pub(crate) struct InstanceBufferPool { pub(crate) struct InstanceBufferPool {
@@ -108,13 +109,19 @@ pub(crate) struct MetalRenderer {
} }
impl MetalRenderer { impl MetalRenderer {
pub fn new(instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>) -> Self { pub fn new(instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>, gpu: Option<Gpu>) -> Self {
// Prefer lowpower integrated GPUs on Intel Mac. On Apple let device = match gpu {
// Silicon, there is only ever one GPU, so this is equivalent to Some(Gpu::Discrete) => metal::Device::system_default(),
// `metal::Device::system_default()`. _ => {
let mut devices = metal::Device::all(); // By default, prefer lowpower integrated GPUs on Intel Mac. On Apple
devices.sort_by_key(|device| (!device.is_removable(), device.is_low_power())); // Silicon, there is only ever one GPU, so this is equivalent to
let Some(device) = devices.pop() else { // `metal::Device::system_default()`.
let mut devices = metal::Device::all();
devices.sort_by_key(|device| (!device.is_removable(), device.is_low_power()));
devices.pop()
}
};
let Some(device) = device else {
log::error!("unable to access a compatible graphics device"); log::error!("unable to access a compatible graphics device");
std::process::exit(1); std::process::exit(1);
}; };

View File

@@ -505,6 +505,7 @@ impl MacWindow {
show, show,
display_id, display_id,
window_min_size, window_min_size,
gpu,
}: WindowParams, }: WindowParams,
executor: ForegroundExecutor, executor: ForegroundExecutor,
renderer_context: renderer::Context, renderer_context: renderer::Context,
@@ -603,6 +604,7 @@ impl MacWindow {
native_view as *mut _, native_view as *mut _,
bounds.size.map(|pixels| pixels.0), bounds.size.map(|pixels| pixels.0),
false, false,
gpu,
), ),
request_frame_callback: None, request_frame_callback: None,
event_callback: None, event_callback: None,

View File

@@ -645,6 +645,7 @@ impl Window {
app_id, app_id,
window_min_size, window_min_size,
window_decorations, window_decorations,
gpu,
} = options; } = options;
let bounds = window_bounds let bounds = window_bounds
@@ -661,6 +662,7 @@ impl Window {
show, show,
display_id, display_id,
window_min_size, window_min_size,
gpu,
}, },
)?; )?;
let display_id = platform_window.display().map(|display| display.id()); let display_id = platform_window.display().map(|display| display.id());

View File

@@ -86,6 +86,7 @@ serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
settings.workspace = true settings.workspace = true
simplelog.workspace = true simplelog.workspace = true
schemars.workspace = true
smol.workspace = true smol.workspace = true
snippet_provider.workspace = true snippet_provider.workspace = true
tab_switcher.workspace = true tab_switcher.workspace = true

View File

@@ -1,4 +1,5 @@
mod app_menus; mod app_menus;
mod gpu;
pub mod inline_completion_registry; pub mod inline_completion_registry;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub(crate) mod linux_prompts; pub(crate) mod linux_prompts;
@@ -11,6 +12,7 @@ use breadcrumbs::Breadcrumbs;
use client::ZED_URL_SCHEME; use client::ZED_URL_SCHEME;
use collections::VecDeque; use collections::VecDeque;
use editor::{scroll::Autoscroll, Editor, MultiBuffer}; use editor::{scroll::Autoscroll, Editor, MultiBuffer};
use gpu::GpuSettings;
use gpui::{ use gpui::{
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel, actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel,
ReadGlobal, TitlebarOptions, View, ViewContext, VisualContext, WindowKind, WindowOptions, ReadGlobal, TitlebarOptions, View, ViewContext, VisualContext, WindowKind, WindowOptions,
@@ -78,6 +80,7 @@ pub fn init(cx: &mut AppContext) {
cx.on_action(|_: &ShowAll, cx| cx.unhide_other_apps()); cx.on_action(|_: &ShowAll, cx| cx.unhide_other_apps());
cx.on_action(quit); cx.on_action(quit);
GpuSettings::register(cx);
if ReleaseChannel::global(cx) == ReleaseChannel::Dev { if ReleaseChannel::global(cx) == ReleaseChannel::Dev {
cx.on_action(test_panic); cx.on_action(test_panic);
} }
@@ -115,6 +118,7 @@ pub fn build_window_options(display_uuid: Option<Uuid>, cx: &mut AppContext) ->
width: px(360.0), width: px(360.0),
height: px(240.0), height: px(240.0),
}), }),
gpu: GpuSettings::get_global(cx).gpu.map(Into::into),
} }
} }

46
crates/zed/src/zed/gpu.rs Normal file
View File

@@ -0,0 +1,46 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
#[derive(Copy, Clone, Debug, Default, Serialize, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Gpu {
Discrete,
#[default]
Integrated,
}
impl Into<gpui::Gpu> for Gpu {
fn into(self) -> gpui::Gpu {
match self {
Gpu::Discrete => gpui::Gpu::Discrete,
Gpu::Integrated => gpui::Gpu::Integrated,
}
}
}
/// Settings related to the machine's GPU and how Zed uses it.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
pub struct GpuSettings {
/// Which GPU to prefer: discrete or integrated.
/// Integrated are often lower-power and thus more battery-efficient.
///
/// Default: 0.2
pub gpu: Option<Gpu>,
}
impl Settings for GpuSettings {
const KEY: Option<&'static str> = None;
type FileContent = Option<Self>;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
if let Some(Some(user_value)) = sources.user.copied() {
return Ok(user_value);
}
Ok(Self::default())
}
}