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",
"repl",
"rope",
"schemars",
"search",
"serde",
"serde_json",

View File

@@ -67,5 +67,6 @@ fn notification_window_options(
app_id: Some(app_id.to_owned()),
window_min_size: None,
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,
window_min_size: 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
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
pub struct WindowControls {
@@ -679,6 +689,10 @@ pub struct WindowOptions {
/// Whether to use client or server side decorations. Wayland only
/// Note that this may be ignored.
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
@@ -707,6 +721,11 @@ pub(crate) struct WindowParams {
#[cfg_attr(target_os = "linux", allow(dead_code))]
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.
@@ -757,6 +776,7 @@ impl Default for WindowOptions {
app_id: None,
window_min_size: None,
window_decorations: None,
gpu: None,
}
}
}

View File

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

View File

@@ -1,7 +1,7 @@
use super::metal_atlas::MetalAtlas;
use crate::{
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,
};
use anyhow::{anyhow, Result};
@@ -38,8 +38,9 @@ pub unsafe fn new_renderer(
_native_view: *mut c_void,
_bounds: crate::Size<f32>,
_transparent: bool,
gpu: Option<Gpu>,
) -> Renderer {
MetalRenderer::new(context)
MetalRenderer::new(context, gpu)
}
pub(crate) struct InstanceBufferPool {
@@ -108,13 +109,19 @@ pub(crate) struct MetalRenderer {
}
impl MetalRenderer {
pub fn new(instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>) -> Self {
// Prefer lowpower integrated GPUs on Intel Mac. On Apple
// Silicon, there is only ever one GPU, so this is equivalent to
// `metal::Device::system_default()`.
let mut devices = metal::Device::all();
devices.sort_by_key(|device| (!device.is_removable(), device.is_low_power()));
let Some(device) = devices.pop() else {
pub fn new(instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>, gpu: Option<Gpu>) -> Self {
let device = match gpu {
Some(Gpu::Discrete) => metal::Device::system_default(),
_ => {
// By default, prefer lowpower integrated GPUs on Intel Mac. On Apple
// Silicon, there is only ever one GPU, so this is equivalent to
// `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");
std::process::exit(1);
};

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
mod app_menus;
mod gpu;
pub mod inline_completion_registry;
#[cfg(target_os = "linux")]
pub(crate) mod linux_prompts;
@@ -11,6 +12,7 @@ use breadcrumbs::Breadcrumbs;
use client::ZED_URL_SCHEME;
use collections::VecDeque;
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
use gpu::GpuSettings;
use gpui::{
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel,
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(quit);
GpuSettings::register(cx);
if ReleaseChannel::global(cx) == ReleaseChannel::Dev {
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),
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())
}
}