diff --git a/Cargo.lock b/Cargo.lock index abe5705761288..8971571f92775 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1750,15 +1750,6 @@ dependencies = [ "bit-vec 0.6.3", ] -[[package]] -name = "bit-set" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" -dependencies = [ - "bit-vec 0.7.0", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -1774,12 +1765,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bit-vec" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" - [[package]] name = "bit-vec" version = "0.8.0" @@ -1828,7 +1813,7 @@ dependencies = [ [[package]] name = "blade-graphics" version = "0.5.0" -source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969" +source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80" dependencies = [ "ash", "ash-window", @@ -1858,7 +1843,7 @@ dependencies = [ [[package]] name = "blade-macros" version = "0.3.0" -source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969" +source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80" dependencies = [ "proc-macro2", "quote", @@ -1868,7 +1853,7 @@ dependencies = [ [[package]] name = "blade-util" version = "0.1.0" -source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969" +source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80" dependencies = [ "blade-graphics", "bytemuck", @@ -7592,9 +7577,8 @@ dependencies = [ [[package]] name = "metal" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +version = "0.30.0" +source = "git+https://github.com/gfx-rs/metal-rs?rev=ef768ff9d742ae6a0f4e83ddc8031264e7d460c4#ef768ff9d742ae6a0f4e83ddc8031264e7d460c4" dependencies = [ "bitflags 2.6.0", "block", @@ -7733,12 +7717,11 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "naga" -version = "22.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" +version = "23.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=1a643291c2e8854ba7e4f5445a4388202731bfa1#1a643291c2e8854ba7e4f5445a4388202731bfa1" dependencies = [ "arrayvec", - "bit-set 0.6.0", + "bit-set 0.8.0", "bitflags 2.6.0", "cfg_aliases 0.1.1", "codespan-reporting", diff --git a/Cargo.toml b/Cargo.toml index 7e5eebca0e229..ee135cd9b5004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -355,9 +355,9 @@ async-watch = "0.3.1" async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] } base64 = "0.22" bitflags = "2.6.0" -blade-graphics = { git = "https://github.com/kvark/blade", rev = "e142a3a5e678eb6a13e642ad8401b1f3aa38e969" } -blade-macros = { git = "https://github.com/kvark/blade", rev = "e142a3a5e678eb6a13e642ad8401b1f3aa38e969" } -blade-util = { git = "https://github.com/kvark/blade", rev = "e142a3a5e678eb6a13e642ad8401b1f3aa38e969" } +blade-graphics = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" } +blade-macros = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" } +blade-util = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" } blake3 = "1.5.3" bytes = "1.0" cargo_metadata = "0.19" @@ -525,6 +525,12 @@ wasmtime-wasi = "24" which = "6.0.0" wit-component = "0.201" zstd = "0.11" +# Custom metal-rs is only needed for "macos-blade" feature of GPUI +#TODO: switch to crates once these are published: +# - https://github.com/gfx-rs/metal-rs/pull/335 +# - https://github.com/gfx-rs/metal-rs/pull/336 +# - https://github.com/gfx-rs/metal-rs/pull/337 +metal = { git = "https://github.com/gfx-rs/metal-rs", rev = "ef768ff9d742ae6a0f4e83ddc8031264e7d460c4" } [workspace.dependencies.async-stripe] git = "https://github.com/zed-industries/async-stripe" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 347d70853ac03..aed1c25168754 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -136,8 +136,8 @@ font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7" foreign-types = "0.5" log.workspace = true media.workspace = true -metal = "0.29" objc = "0.2" +metal.workspace = true [target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))'.dependencies] pathfinder_geometry = "0.5" diff --git a/crates/gpui/src/platform/blade.rs b/crates/gpui/src/platform/blade.rs index 736c1888d894c..9d966d8a4e069 100644 --- a/crates/gpui/src/platform/blade.rs +++ b/crates/gpui/src/platform/blade.rs @@ -1,5 +1,11 @@ +#[cfg(target_os = "macos")] +mod apple_compat; mod blade_atlas; +mod blade_context; mod blade_renderer; +#[cfg(target_os = "macos")] +pub(crate) use apple_compat::*; pub(crate) use blade_atlas::*; +pub(crate) use blade_context::*; pub(crate) use blade_renderer::*; diff --git a/crates/gpui/src/platform/blade/apple_compat.rs b/crates/gpui/src/platform/blade/apple_compat.rs new file mode 100644 index 0000000000000..b1baab8854aca --- /dev/null +++ b/crates/gpui/src/platform/blade/apple_compat.rs @@ -0,0 +1,60 @@ +use super::{BladeContext, BladeRenderer, BladeSurfaceConfig}; +use blade_graphics as gpu; +use std::{ffi::c_void, ptr::NonNull}; + +#[derive(Clone)] +pub struct Context { + inner: BladeContext, +} +impl Default for Context { + fn default() -> Self { + Self { + inner: BladeContext::new().unwrap(), + } + } +} + +pub type Renderer = BladeRenderer; + +pub unsafe fn new_renderer( + context: Context, + _native_window: *mut c_void, + native_view: *mut c_void, + bounds: crate::Size, + transparent: bool, +) -> Renderer { + use raw_window_handle as rwh; + struct RawWindow { + view: *mut c_void, + } + + impl rwh::HasWindowHandle for RawWindow { + fn window_handle(&self) -> Result { + let view = NonNull::new(self.view).unwrap(); + let handle = rwh::AppKitWindowHandle::new(view); + Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) }) + } + } + impl rwh::HasDisplayHandle for RawWindow { + fn display_handle(&self) -> Result { + let handle = rwh::AppKitDisplayHandle::new(); + Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) }) + } + } + + BladeRenderer::new( + &context.inner, + &RawWindow { + view: native_view as *mut _, + }, + BladeSurfaceConfig { + size: gpu::Extent { + width: bounds.width as u32, + height: bounds.height as u32, + depth: 1, + }, + transparent, + }, + ) + .unwrap() +} diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index b876d5bb9be9e..9e666d71bf02f 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -268,7 +268,7 @@ impl BladeAtlasState { fn flush(&mut self, encoder: &mut gpu::CommandEncoder) { self.flush_initializations(encoder); - let mut transfers = encoder.transfer(); + let mut transfers = encoder.transfer("atlas"); for upload in self.uploads.drain(..) { let texture = &self.storage[upload.id]; transfers.copy_buffer_to_texture( diff --git a/crates/gpui/src/platform/blade/blade_context.rs b/crates/gpui/src/platform/blade/blade_context.rs new file mode 100644 index 0000000000000..f03fff01e0539 --- /dev/null +++ b/crates/gpui/src/platform/blade/blade_context.rs @@ -0,0 +1,24 @@ +use blade_graphics as gpu; +use std::sync::Arc; + +#[cfg_attr(target_os = "macos", derive(Clone))] +pub struct BladeContext { + pub(super) gpu: Arc, +} + +impl BladeContext { + pub fn new() -> anyhow::Result { + let gpu = Arc::new( + unsafe { + gpu::Context::init(gpu::ContextDesc { + presentation: true, + validation: false, + device_id: 0, //TODO: hook up to user settings + ..Default::default() + }) + } + .map_err(|e| anyhow::anyhow!("{:?}", e))?, + ); + Ok(Self { gpu }) + } +} diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 92becf2342446..55a53e8e9f705 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -1,7 +1,7 @@ // Doing `if let` gives you nice scoping with passes/encoders #![allow(irrefutable_let_patterns)] -use super::{BladeAtlas, PATH_TEXTURE_FORMAT}; +use super::{BladeAtlas, BladeContext, PATH_TEXTURE_FORMAT}; use crate::{ AtlasTextureKind, AtlasTile, Background, Bounds, ContentMask, DevicePixels, GpuSpecs, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, @@ -11,8 +11,6 @@ use bytemuck::{Pod, Zeroable}; use collections::HashMap; #[cfg(target_os = "macos")] use media::core_video::CVMetalTextureCache; -#[cfg(target_os = "macos")] -use std::{ffi::c_void, ptr::NonNull}; use blade_graphics as gpu; use blade_util::{BufferBelt, BufferBeltDescriptor}; @@ -20,66 +18,6 @@ use std::{mem, sync::Arc}; const MAX_FRAME_TIME_MS: u32 = 10000; -#[cfg(target_os = "macos")] -#[derive(Clone, Default)] -pub struct Context {} -#[cfg(target_os = "macos")] -pub type Renderer = BladeRenderer; - -#[cfg(target_os = "macos")] -pub unsafe fn new_renderer( - _context: self::Context, - _native_window: *mut c_void, - native_view: *mut c_void, - bounds: crate::Size, - transparent: bool, -) -> Renderer { - use raw_window_handle as rwh; - struct RawWindow { - view: *mut c_void, - } - - impl rwh::HasWindowHandle for RawWindow { - fn window_handle(&self) -> Result { - let view = NonNull::new(self.view).unwrap(); - let handle = rwh::AppKitWindowHandle::new(view); - Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) }) - } - } - impl rwh::HasDisplayHandle for RawWindow { - fn display_handle(&self) -> Result { - let handle = rwh::AppKitDisplayHandle::new(); - Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) }) - } - } - - let gpu = Arc::new( - gpu::Context::init_windowed( - &RawWindow { - view: native_view as *mut _, - }, - gpu::ContextDesc { - validation: cfg!(debug_assertions), - capture: false, - overlay: false, - }, - ) - .unwrap(), - ); - - BladeRenderer::new( - gpu, - BladeSurfaceConfig { - size: gpu::Extent { - width: bounds.width as u32, - height: bounds.height as u32, - depth: 1, - }, - transparent, - }, - ) -} - #[repr(C)] #[derive(Clone, Copy, Pod, Zeroable)] struct GlobalParams { @@ -354,10 +292,14 @@ pub struct BladeSurfaceConfig { pub transparent: bool, } +//Note: we could see some of these fields moved into `BladeContext` +// so that they are shared between windows. E.g. `pipelines`. +// But that is complicated by the fact that pipelines depend on +// the format and alpha mode. pub struct BladeRenderer { gpu: Arc, + surface: gpu::Surface, surface_config: gpu::SurfaceConfig, - alpha_mode: gpu::AlphaMode, command_encoder: gpu::CommandEncoder, last_sync_point: Option, pipelines: BladePipelines, @@ -370,7 +312,11 @@ pub struct BladeRenderer { } impl BladeRenderer { - pub fn new(gpu: Arc, config: BladeSurfaceConfig) -> Self { + pub fn new( + context: &BladeContext, + window: &I, + config: BladeSurfaceConfig, + ) -> anyhow::Result { let surface_config = gpu::SurfaceConfig { size: config.size, usage: gpu::TextureUsage::TARGET, @@ -379,20 +325,23 @@ impl BladeRenderer { allow_exclusive_full_screen: false, transparent: config.transparent, }; - let surface_info = gpu.resize(surface_config); + let surface = context + .gpu + .create_surface_configured(window, surface_config) + .unwrap(); - let command_encoder = gpu.create_command_encoder(gpu::CommandEncoderDesc { + let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", buffer_count: 2, }); - let pipelines = BladePipelines::new(&gpu, surface_info); + let pipelines = BladePipelines::new(&context.gpu, surface.info()); let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe }); - let atlas = Arc::new(BladeAtlas::new(&gpu)); - let atlas_sampler = gpu.create_sampler(gpu::SamplerDesc { + let atlas = Arc::new(BladeAtlas::new(&context.gpu)); + let atlas_sampler = context.gpu.create_sampler(gpu::SamplerDesc { name: "atlas", mag_filter: gpu::FilterMode::Linear, min_filter: gpu::FilterMode::Linear, @@ -402,13 +351,13 @@ impl BladeRenderer { #[cfg(target_os = "macos")] let core_video_texture_cache = unsafe { use foreign_types::ForeignType as _; - CVMetalTextureCache::new(gpu.metal_device().as_ptr()).unwrap() + CVMetalTextureCache::new(context.gpu.metal_device().as_ptr()).unwrap() }; - Self { - gpu, + Ok(Self { + gpu: Arc::clone(&context.gpu), + surface, surface_config, - alpha_mode: surface_info.alpha, command_encoder, last_sync_point: None, pipelines, @@ -418,7 +367,7 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, - } + }) } fn wait_for_gpu(&mut self) { @@ -452,7 +401,8 @@ impl BladeRenderer { if always_resize || gpu_size != self.surface_config.size { self.wait_for_gpu(); self.surface_config.size = gpu_size; - self.gpu.resize(self.surface_config); + self.gpu + .reconfigure_surface(&mut self.surface, self.surface_config); } } @@ -460,10 +410,10 @@ impl BladeRenderer { if transparent != self.surface_config.transparent { self.wait_for_gpu(); self.surface_config.transparent = transparent; - let surface_info = self.gpu.resize(self.surface_config); + self.gpu + .reconfigure_surface(&mut self.surface, self.surface_config); self.pipelines.destroy(&self.gpu); - self.pipelines = BladePipelines::new(&self.gpu, surface_info); - self.alpha_mode = surface_info.alpha; + self.pipelines = BladePipelines::new(&self.gpu, self.surface.info()); } } @@ -490,13 +440,13 @@ impl BladeRenderer { #[cfg(target_os = "macos")] pub fn layer(&self) -> metal::MetalLayer { - self.gpu.metal_layer().unwrap() + self.surface.metal_layer() } #[cfg(target_os = "macos")] pub fn layer_ptr(&self) -> *mut metal::CAMetalLayer { use metal::foreign_types::ForeignType as _; - self.gpu.metal_layer().unwrap().as_ptr() + self.surface.metal_layer().as_ptr() } #[profiling::function] @@ -538,14 +488,17 @@ impl BladeRenderer { }; let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) }; - let mut pass = self.command_encoder.render(gpu::RenderTargetSet { - colors: &[gpu::RenderTarget { - view: tex_info.raw_view, - init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), - finish_op: gpu::FinishOp::Store, - }], - depth_stencil: None, - }); + let mut pass = self.command_encoder.render( + "paths", + gpu::RenderTargetSet { + colors: &[gpu::RenderTarget { + view: tex_info.raw_view, + init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), + finish_op: gpu::FinishOp::Store, + }], + depth_stencil: None, + }, + ); let mut encoder = pass.with(&self.pipelines.path_rasterization); encoder.bind( @@ -566,6 +519,7 @@ impl BladeRenderer { self.instance_belt.destroy(&self.gpu); self.gpu.destroy_command_encoder(&mut self.command_encoder); self.pipelines.destroy(&self.gpu); + self.gpu.destroy_surface(&mut self.surface); } pub fn draw(&mut self, scene: &Scene) { @@ -575,7 +529,7 @@ impl BladeRenderer { let frame = { profiling::scope!("acquire frame"); - self.gpu.acquire_frame() + self.surface.acquire_frame() }; self.command_encoder.init_texture(frame.texture()); @@ -584,21 +538,24 @@ impl BladeRenderer { self.surface_config.size.width as f32, self.surface_config.size.height as f32, ], - premultiplied_alpha: match self.alpha_mode { + premultiplied_alpha: match self.surface.info().alpha { gpu::AlphaMode::Ignored | gpu::AlphaMode::PostMultiplied => 0, gpu::AlphaMode::PreMultiplied => 1, }, pad: 0, }; - if let mut pass = self.command_encoder.render(gpu::RenderTargetSet { - colors: &[gpu::RenderTarget { - view: frame.texture_view(), - init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), - finish_op: gpu::FinishOp::Store, - }], - depth_stencil: None, - }) { + if let mut pass = self.command_encoder.render( + "main", + gpu::RenderTargetSet { + colors: &[gpu::RenderTarget { + view: frame.texture_view(), + init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), + finish_op: gpu::FinishOp::Store, + }], + depth_stencil: None, + }, + ) { profiling::scope!("render pass"); for batch in scene.batches() { match batch { diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index d0c0f1768e0f6..c5a39fddd8c59 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -1,52 +1,45 @@ -#![allow(unused)] - -use std::any::{type_name, Any}; -use std::cell::{self, RefCell}; -use std::env; -use std::ffi::OsString; -use std::fs::File; -use std::io::Read; -use std::ops::{Deref, DerefMut}; -use std::os::fd::{AsFd, AsRawFd, FromRawFd}; -use std::panic::{AssertUnwindSafe, Location}; -use std::rc::Weak; use std::{ + env, + panic::AssertUnwindSafe, path::{Path, PathBuf}, process::Command, rc::Rc, sync::Arc, +}; +#[cfg(any(feature = "wayland", feature = "x11"))] +use std::{ + ffi::OsString, + fs::File, + io::Read as _, + os::fd::{AsFd, AsRawFd, FromRawFd}, time::Duration, }; use anyhow::{anyhow, Context as _}; use async_task::Runnable; -use calloop::channel::Channel; -use calloop::{EventLoop, LoopHandle, LoopSignal}; -use flume::{Receiver, Sender}; +use calloop::{channel::Channel, LoopSignal}; use futures::{channel::oneshot, future::FutureExt}; -use parking_lot::Mutex; -use util::ResultExt; - +use util::ResultExt as _; #[cfg(any(feature = "wayland", feature = "x11"))] use xkbcommon::xkb::{self, Keycode, Keysym, State}; -use crate::platform::NoopTextSystem; use crate::{ px, Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, - ForegroundExecutor, Keymap, Keystroke, LinuxDispatcher, Menu, MenuItem, Modifiers, OwnedMenu, - PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformInputHandler, PlatformTextSystem, - PlatformWindow, Point, PromptLevel, Result, ScreenCaptureSource, SemanticVersion, SharedString, - Size, Task, WindowAppearance, WindowOptions, WindowParams, + ForegroundExecutor, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu, PathPromptOptions, + Pixels, Platform, PlatformDisplay, PlatformTextSystem, PlatformWindow, Point, Result, + ScreenCaptureSource, Task, WindowAppearance, WindowParams, }; - +#[cfg(any(feature = "wayland", feature = "x11"))] pub(crate) const SCROLL_LINES: f32 = 3.0; // Values match the defaults on GTK. // Taken from https://github.com/GNOME/gtk/blob/main/gtk/gtksettings.c#L320 +#[cfg(any(feature = "wayland", feature = "x11"))] pub(crate) const DOUBLE_CLICK_INTERVAL: Duration = Duration::from_millis(400); pub(crate) const DOUBLE_CLICK_DISTANCE: Pixels = px(5.0); pub(crate) const KEYRING_LABEL: &str = "zed-github-account"; +#[cfg(any(feature = "wayland", feature = "x11"))] const FILE_PICKER_PORTAL_MISSING: &str = "Couldn't open file picker due to missing xdg-desktop-portal implementation."; @@ -54,8 +47,9 @@ pub trait LinuxClient { fn compositor_name(&self) -> &'static str; fn with_common(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R; fn displays(&self) -> Vec>; - fn primary_display(&self) -> Option>; + #[allow(unused)] fn display(&self, id: DisplayId) -> Option>; + fn primary_display(&self) -> Option>; fn open_window( &self, @@ -98,9 +92,9 @@ pub(crate) struct LinuxCommon { impl LinuxCommon { pub fn new(signal: LoopSignal) -> (Self, Channel) { let (main_sender, main_receiver) = calloop::channel::channel::(); + #[cfg(any(feature = "wayland", feature = "x11"))] let text_system = Arc::new(crate::CosmicTextSystem::new()); - #[cfg(not(any(feature = "wayland", feature = "x11")))] let text_system = Arc::new(crate::NoopTextSystem::new()); @@ -218,7 +212,7 @@ impl Platform for P { } } - fn activate(&self, ignoring_other_apps: bool) { + fn activate(&self, _ignoring_other_apps: bool) { log::info!("activate is not implemented on Linux, ignoring the call") } @@ -281,7 +275,7 @@ impl Platform for P { let (done_tx, done_rx) = oneshot::channel(); #[cfg(not(any(feature = "wayland", feature = "x11")))] - done_tx.send(Ok(None)); + let _ = (done_tx.send(Ok(None)), options); #[cfg(any(feature = "wayland", feature = "x11"))] self.foreground_executor() @@ -306,7 +300,7 @@ impl Platform for P { ashpd::Error::PortalNotFound(_) => anyhow!(FILE_PICKER_PORTAL_MISSING), err => err.into(), }; - done_tx.send(Err(result)); + let _ = done_tx.send(Err(result)); return; } }; @@ -322,7 +316,7 @@ impl Platform for P { Err(ashpd::Error::Response(_)) => Ok(None), Err(e) => Err(e.into()), }; - done_tx.send(result); + let _ = done_tx.send(result); }) .detach(); done_rx @@ -332,7 +326,7 @@ impl Platform for P { let (done_tx, done_rx) = oneshot::channel(); #[cfg(not(any(feature = "wayland", feature = "x11")))] - done_tx.send(Ok(None)); + let _ = (done_tx.send(Ok(None)), directory); #[cfg(any(feature = "wayland", feature = "x11"))] self.foreground_executor() @@ -356,7 +350,7 @@ impl Platform for P { } err => err.into(), }; - done_tx.send(Err(result)); + let _ = done_tx.send(Err(result)); return; } }; @@ -369,7 +363,7 @@ impl Platform for P { Err(ashpd::Error::Response(_)) => Ok(None), Err(e) => Err(e.into()), }; - done_tx.send(result); + let _ = done_tx.send(result); } }) .detach(); @@ -426,7 +420,7 @@ impl Platform for P { fn app_path(&self) -> Result { // get the path of the executable of the current process - let exe_path = std::env::current_exe()?; + let exe_path = env::current_exe()?; Ok(exe_path) } @@ -440,9 +434,9 @@ impl Platform for P { self.with_common(|common| Some(common.menus.clone())) } - fn set_dock_menu(&self, menu: Vec, keymap: &Keymap) {} + fn set_dock_menu(&self, _menu: Vec, _keymap: &Keymap) {} - fn path_for_auxiliary_executable(&self, name: &str) -> Result { + fn path_for_auxiliary_executable(&self, _name: &str) -> Result { Err(anyhow::Error::msg( "Platform::path_for_auxiliary_executable is not implemented yet", )) @@ -614,6 +608,7 @@ pub(super) fn reveal_path_internal( .detach(); } +#[allow(unused)] pub(super) fn is_within_click_distance(a: Point, b: Point) -> bool { let diff = a - b; diff.x.abs() <= DOUBLE_CLICK_DISTANCE && diff.y.abs() <= DOUBLE_CLICK_DISTANCE @@ -622,7 +617,7 @@ pub(super) fn is_within_click_distance(a: Point, b: Point) -> bo #[cfg(any(feature = "wayland", feature = "x11"))] pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option { let mut locales = Vec::default(); - if let Some(locale) = std::env::var_os("LC_CTYPE") { + if let Some(locale) = env::var_os("LC_CTYPE") { locales.push(locale); } locales.push(OsString::from("C")); @@ -650,6 +645,7 @@ pub(super) unsafe fn read_fd(mut fd: filedescriptor::FileDescriptor) -> Result String { // Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME) // and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from @@ -682,10 +678,12 @@ impl CursorStyle { } #[cfg(any(feature = "wayland", feature = "x11"))] -impl Keystroke { - pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self { - let mut modifiers = modifiers; - +impl crate::Keystroke { + pub(super) fn from_xkb( + state: &State, + mut modifiers: crate::Modifiers, + keycode: Keycode, + ) -> Self { let key_utf32 = state.key_get_utf32(keycode); let key_utf8 = state.key_get_utf8(keycode); let key_sym = state.key_get_one_sym(keycode); @@ -759,7 +757,7 @@ impl Keystroke { let key_char = (key_utf32 >= 32 && key_utf32 != 127 && !key_utf8.is_empty()).then_some(key_utf8); - Keystroke { + Self { modifiers, key, key_char, @@ -776,7 +774,6 @@ impl Keystroke { Keysym::dead_acute => Some("´".to_owned()), Keysym::dead_circumflex => Some("^".to_owned()), Keysym::dead_tilde => Some("~".to_owned()), - Keysym::dead_perispomeni => Some("͂".to_owned()), Keysym::dead_macron => Some("¯".to_owned()), Keysym::dead_breve => Some("˘".to_owned()), Keysym::dead_abovedot => Some("˙".to_owned()), @@ -794,9 +791,7 @@ impl Keystroke { Keysym::dead_horn => Some("̛".to_owned()), Keysym::dead_stroke => Some("̶̶".to_owned()), Keysym::dead_abovecomma => Some("̓̓".to_owned()), - Keysym::dead_psili => Some("᾿".to_owned()), Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()), - Keysym::dead_dasia => Some("῾".to_owned()), Keysym::dead_doublegrave => Some("̏".to_owned()), Keysym::dead_belowring => Some("˳".to_owned()), Keysym::dead_belowmacron => Some("̱".to_owned()), @@ -830,7 +825,7 @@ impl Keystroke { } #[cfg(any(feature = "wayland", feature = "x11"))] -impl Modifiers { +impl crate::Modifiers { pub(super) fn from_xkb(keymap_state: &State) -> Self { let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE); let alt = keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE); @@ -838,7 +833,7 @@ impl Modifiers { keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE); let platform = keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE); - Modifiers { + Self { shift, alt, control, diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 2cafffa72534d..622f4587542b0 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -1,12 +1,16 @@ -use std::cell::{RefCell, RefMut}; -use std::hash::Hash; -use std::os::fd::{AsRawFd, BorrowedFd}; -use std::path::PathBuf; -use std::rc::{Rc, Weak}; -use std::time::{Duration, Instant}; - -use calloop::timer::{TimeoutAction, Timer}; -use calloop::{EventLoop, LoopHandle}; +use std::{ + cell::{RefCell, RefMut}, + hash::Hash, + os::fd::{AsRawFd, BorrowedFd}, + path::PathBuf, + rc::{Rc, Weak}, + time::{Duration, Instant}, +}; + +use calloop::{ + timer::{TimeoutAction, Timer}, + EventLoop, LoopHandle, +}; use calloop_wayland_source::WaylandSource; use collections::HashMap; use filedescriptor::Pipe; @@ -64,30 +68,28 @@ use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS}; use super::display::WaylandDisplay; use super::window::{ImeInput, WaylandWindowStatePtr}; -use crate::platform::linux::wayland::clipboard::{ - Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPE, -}; -use crate::platform::linux::wayland::cursor::Cursor; -use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker}; -use crate::platform::linux::wayland::window::WaylandWindow; -use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}; -use crate::platform::linux::LinuxClient; + use crate::platform::linux::{ get_xkb_compose_state, is_within_click_distance, open_uri_internal, read_fd, reveal_path_internal, + wayland::{ + clipboard::{Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPE}, + cursor::Cursor, + serial::{SerialKind, SerialTracker}, + window::WaylandWindow, + }, + xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, + LinuxClient, }; -use crate::platform::PlatformWindow; -use crate::{ - point, px, size, Bounds, DevicePixels, FileDropEvent, ForegroundExecutor, MouseExitEvent, Size, - DOUBLE_CLICK_INTERVAL, SCROLL_LINES, -}; +use crate::platform::{blade::BladeContext, PlatformWindow}; use crate::{ - AnyWindowHandle, CursorStyle, DisplayId, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, - ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, - NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScaledPixels, ScrollDelta, - ScrollWheelEvent, TouchPhase, + point, px, size, AnyWindowHandle, Bounds, CursorStyle, DevicePixels, DisplayId, FileDropEvent, + ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, Modifiers, + ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, + MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScaledPixels, + ScrollDelta, ScrollWheelEvent, Size, TouchPhase, WindowParams, DOUBLE_CLICK_INTERVAL, + SCROLL_LINES, }; -use crate::{LinuxCommon, WindowParams}; /// Used to convert evdev scancode to xkb scancode const MIN_KEYCODE: u32 = 8; @@ -186,6 +188,7 @@ pub struct Output { pub(crate) struct WaylandClientState { serial_tracker: SerialTracker, globals: Globals, + gpu_context: BladeContext, wl_seat: wl_seat::WlSeat, // TODO: Multi seat support wl_pointer: Option, wl_keyboard: Option, @@ -459,6 +462,8 @@ impl WaylandClient { }) .unwrap(); + let gpu_context = BladeContext::new().expect("Unable to init GPU context"); + let seat = seat.unwrap(); let globals = Globals::new( globals, @@ -512,6 +517,7 @@ impl WaylandClient { let mut state = Rc::new(RefCell::new(WaylandClientState { serial_tracker: SerialTracker::new(), globals, + gpu_context, wl_seat: seat, wl_pointer: None, wl_keyboard: None, @@ -627,6 +633,7 @@ impl LinuxClient for WaylandClient { let (window, surface_id) = WaylandWindow::new( handle, state.globals.clone(), + &state.gpu_context, WaylandClientStatePtr(Rc::downgrade(&self.0)), params, state.common.appearance, diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index bb0485272b70d..bb1a687c32eb8 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -1,8 +1,10 @@ -use std::cell::{Ref, RefCell, RefMut}; -use std::ffi::c_void; -use std::ptr::NonNull; -use std::rc::Rc; -use std::sync::Arc; +use std::{ + cell::{Ref, RefCell, RefMut}, + ffi::c_void, + ptr::NonNull, + rc::Rc, + sync::Arc, +}; use blade_graphics as gpu; use collections::HashMap; @@ -19,10 +21,11 @@ use wayland_protocols::xdg::shell::client::xdg_surface; use wayland_protocols::xdg::shell::client::xdg_toplevel::{self}; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur; -use crate::platform::blade::{BladeRenderer, BladeSurfaceConfig}; -use crate::platform::linux::wayland::display::WaylandDisplay; -use crate::platform::linux::wayland::serial::SerialKind; -use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow}; +use crate::platform::{ + blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}, + linux::wayland::{display::WaylandDisplay, serial::SerialKind}, + PlatformAtlas, PlatformInputHandler, PlatformWindow, +}; use crate::scene::Scene; use crate::{ px, size, AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, @@ -123,37 +126,28 @@ impl WaylandWindowState { viewport: Option, client: WaylandClientStatePtr, globals: Globals, + gpu_context: &BladeContext, options: WindowParams, ) -> anyhow::Result { - let raw = RawWindow { - window: surface.id().as_ptr().cast::(), - display: surface - .backend() - .upgrade() - .unwrap() - .display_ptr() - .cast::(), - }; - let gpu = Arc::new( - unsafe { - gpu::Context::init_windowed( - &raw, - gpu::ContextDesc { - validation: false, - capture: false, - overlay: false, - }, - ) - } - .map_err(|e| anyhow::anyhow!("{:?}", e))?, - ); - let config = BladeSurfaceConfig { - size: gpu::Extent { - width: options.bounds.size.width.0 as u32, - height: options.bounds.size.height.0 as u32, - depth: 1, - }, - transparent: true, + let renderer = { + let raw_window = RawWindow { + window: surface.id().as_ptr().cast::(), + display: surface + .backend() + .upgrade() + .unwrap() + .display_ptr() + .cast::(), + }; + let config = BladeSurfaceConfig { + size: gpu::Extent { + width: options.bounds.size.width.0 as u32, + height: options.bounds.size.height.0 as u32, + depth: 1, + }, + transparent: true, + }; + BladeRenderer::new(gpu_context, &raw_window, config)? }; Ok(Self { @@ -168,7 +162,7 @@ impl WaylandWindowState { globals, outputs: HashMap::default(), display: None, - renderer: BladeRenderer::new(gpu, config), + renderer, bounds: options.bounds, scale: 1.0, input_handler: None, @@ -266,6 +260,7 @@ impl WaylandWindow { pub fn new( handle: AnyWindowHandle, globals: Globals, + gpu_context: &BladeContext, client: WaylandClientStatePtr, params: WindowParams, appearance: WindowAppearance, @@ -308,6 +303,7 @@ impl WaylandWindow { viewport, client, globals, + gpu_context, params, )?)), callbacks: Rc::new(RefCell::new(Callbacks::default())), diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index a0c9ab47943fb..dd6b022fa0a8a 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -1,13 +1,17 @@ use core::str; -use std::cell::RefCell; -use std::collections::{BTreeMap, HashSet}; -use std::ops::Deref; -use std::path::PathBuf; -use std::rc::{Rc, Weak}; -use std::time::{Duration, Instant}; +use std::{ + cell::RefCell, + collections::{BTreeMap, HashSet}, + ops::Deref, + path::PathBuf, + rc::{Rc, Weak}, + time::{Duration, Instant}, +}; -use calloop::generic::{FdWrapper, Generic}; -use calloop::{EventLoop, LoopHandle, RegistrationToken}; +use calloop::{ + generic::{FdWrapper, Generic}, + EventLoop, LoopHandle, RegistrationToken, +}; use anyhow::Context as _; use collections::HashMap; @@ -15,44 +19,49 @@ use http_client::Url; use smallvec::SmallVec; use util::ResultExt; -use x11rb::connection::{Connection, RequestConnection}; -use x11rb::cursor; -use x11rb::errors::ConnectionError; -use x11rb::protocol::randr::ConnectionExt as _; -use x11rb::protocol::xinput::ConnectionExt; -use x11rb::protocol::xkb::ConnectionExt as _; -use x11rb::protocol::xproto::{ - AtomEnum, ChangeWindowAttributesAux, ClientMessageData, ClientMessageEvent, ConnectionExt as _, - EventMask, KeyPressEvent, +use x11rb::{ + connection::{Connection, RequestConnection}, + cursor, + errors::ConnectionError, + protocol::randr::ConnectionExt as _, + protocol::xinput::ConnectionExt, + protocol::xkb::ConnectionExt as _, + protocol::xproto::{ + AtomEnum, ChangeWindowAttributesAux, ClientMessageData, ClientMessageEvent, + ConnectionExt as _, EventMask, KeyPressEvent, + }, + protocol::{randr, render, xinput, xkb, xproto, Event}, + resource_manager::Database, + wrapper::ConnectionExt as _, + xcb_ffi::XCBConnection, }; -use x11rb::protocol::{randr, render, xinput, xkb, xproto, Event}; -use x11rb::resource_manager::Database; -use x11rb::wrapper::ConnectionExt as _; -use x11rb::xcb_ffi::XCBConnection; -use xim::{x11rb::X11rbClient, Client}; -use xim::{AttributeName, InputStyle}; +use xim::{x11rb::X11rbClient, AttributeName, Client, InputStyle}; use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION}; use xkbcommon::xkb::{self as xkbc, LayoutIndex, ModMask}; -use crate::platform::linux::LinuxClient; -use crate::platform::{LinuxCommon, PlatformWindow}; -use crate::{ - modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle, - DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, Pixels, - Platform, PlatformDisplay, PlatformInput, Point, RequestFrameOptions, ScaledPixels, - ScrollDelta, Size, TouchPhase, WindowParams, X11Window, -}; - use super::{ button_or_scroll_from_event_detail, get_valuator_axis_index, modifiers_from_state, pressed_button_from_mask, ButtonOrScroll, ScrollDirection, }; use super::{X11Display, X11WindowStatePtr, XcbAtoms}; use super::{XimCallbackEvent, XimHandler}; -use crate::platform::linux::platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES}; -use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}; -use crate::platform::linux::{ - get_xkb_compose_state, is_within_click_distance, open_uri_internal, reveal_path_internal, + +use crate::platform::{ + blade::BladeContext, + linux::{ + get_xkb_compose_state, is_within_click_distance, open_uri_internal, + platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES}, + reveal_path_internal, + xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, + LinuxClient, + }, + LinuxCommon, PlatformWindow, +}; +use crate::{ + modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle, + DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, Pixels, + Platform, PlatformDisplay, PlatformInput, Point, RequestFrameOptions, ScaledPixels, + ScrollDelta, Size, TouchPhase, WindowParams, X11Window, }; /// Value for DeviceId parameters which selects all devices. @@ -158,6 +167,8 @@ pub struct X11ClientState { pub(crate) last_location: Point, pub(crate) current_count: usize, + gpu_context: BladeContext, + pub(crate) scale_factor: f32, xkb_context: xkbc::Context, @@ -360,6 +371,8 @@ impl X11Client { let compose_state = get_xkb_compose_state(&xkb_context); let resource_database = x11rb::resource_manager::new_from_default(&xcb_connection).unwrap(); + let gpu_context = BladeContext::new().expect("Unable to init GPU context"); + let scale_factor = resource_database .get_value("Xft.dpi", "Xft.dpi") .ok() @@ -428,6 +441,7 @@ impl X11Client { last_mouse_button: None, last_location: Point::new(px(0.0), px(0.0)), current_count: 0, + gpu_context, scale_factor, xkb_context, @@ -1299,6 +1313,7 @@ impl LinuxClient for X11Client { handle, X11ClientStatePtr(Rc::downgrade(&self.0)), state.common.foreground_executor.clone(), + &state.gpu_context, params, &state.xcb_connection, state.client_side_decorations_supported, diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 8fb378072f108..9a685773a2c85 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Context}; +use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}; use crate::{ - platform::blade::{BladeRenderer, BladeSurfaceConfig}, px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GpuSpecs, Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size, @@ -247,7 +247,6 @@ pub struct X11WindowState { x_root_window: xproto::Window, pub(crate) counter_id: sync::Counter, pub(crate) last_sync_counter: Option, - _raw: RawWindow, bounds: Bounds, scale_factor: f32, renderer: BladeRenderer, @@ -358,6 +357,7 @@ impl X11WindowState { handle: AnyWindowHandle, client: X11ClientStatePtr, executor: ForegroundExecutor, + gpu_context: &BladeContext, params: WindowParams, xcb: &Rc, client_side_decorations_supported: bool, @@ -555,50 +555,39 @@ impl X11WindowState { xcb.flush().with_context(|| "X11 Flush failed.")?; - let raw = RawWindow { - connection: as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection(xcb) - as *mut _, - screen_id: x_screen_index, - window_id: x_window, - visual_id: visual.id, + let renderer = { + let raw_window = RawWindow { + connection: as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection( + xcb, + ) as *mut _, + screen_id: x_screen_index, + window_id: x_window, + visual_id: visual.id, + }; + let config = BladeSurfaceConfig { + // Note: this has to be done after the GPU init, or otherwise + // the sizes are immediately invalidated. + size: query_render_extent(xcb, x_window)?, + // We set it to transparent by default, even if we have client-side + // decorations, since those seem to work on X11 even without `true` here. + // If the window appearance changes, then the renderer will get updated + // too + transparent: false, + }; + BladeRenderer::new(gpu_context, &raw_window, config)? }; - let gpu = Arc::new( - unsafe { - gpu::Context::init_windowed( - &raw, - gpu::ContextDesc { - validation: false, - capture: false, - overlay: false, - }, - ) - } - .map_err(|e| anyhow!("{:?}", e))?, - ); - let config = BladeSurfaceConfig { - // Note: this has to be done after the GPU init, or otherwise - // the sizes are immediately invalidated. - size: query_render_extent(xcb, x_window)?, - // We set it to transparent by default, even if we have client-side - // decorations, since those seem to work on X11 even without `true` here. - // If the window appearance changes, then the renderer will get updated - // too - transparent: false, - }; check_reply(|| "X11 MapWindow failed.", xcb.map_window(x_window))?; - let display = Rc::new(X11Display::new(xcb, scale_factor, x_screen_index)?); Ok(Self { client, executor, display, - _raw: raw, x_root_window: visual_set.root, bounds: bounds.to_pixels(scale_factor), scale_factor, - renderer: BladeRenderer::new(gpu, config), + renderer, atoms: *atoms, input_handler: None, active: false, @@ -716,6 +705,7 @@ impl X11Window { handle: AnyWindowHandle, client: X11ClientStatePtr, executor: ForegroundExecutor, + gpu_context: &BladeContext, params: WindowParams, xcb: &Rc, client_side_decorations_supported: bool, @@ -730,6 +720,7 @@ impl X11Window { handle, client, executor, + gpu_context, params, xcb, client_side_decorations_supported, diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 0c23a4ef7ad14..1da9dbc0cf30e 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -28,11 +28,12 @@ use windows::{ UI::ViewManagement::UISettings, }; -use crate::*; +use crate::{platform::blade::BladeContext, *}; pub(crate) struct WindowsPlatform { state: RefCell, raw_window_handles: RwLock>, + gpu_context: BladeContext, // The below members will never change throughout the entire lifecycle of the app. icon: HICON, main_receiver: flume::Receiver, @@ -94,12 +95,14 @@ impl WindowsPlatform { let icon = load_icon().unwrap_or_default(); let state = RefCell::new(WindowsPlatformState::new()); let raw_window_handles = RwLock::new(SmallVec::new()); + let gpu_context = BladeContext::new().expect("Unable to init GPU context"); let windows_version = WindowsVersion::new().expect("Error retrieve windows version"); let validation_number = rand::random::(); Self { state, raw_window_handles, + gpu_context, icon, main_receiver, dispatch_event, @@ -344,7 +347,12 @@ impl Platform for WindowsPlatform { handle: AnyWindowHandle, options: WindowParams, ) -> Result> { - let window = WindowsWindow::new(handle, options, self.generate_creation_info())?; + let window = WindowsWindow::new( + handle, + options, + self.generate_creation_info(), + &self.gpu_context, + )?; let handle = window.get_raw_handle(); self.raw_window_handles.write().push(handle); diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index be3deab631032..cb8bde647d594 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -27,7 +27,7 @@ use windows::{ }, }; -use crate::platform::blade::BladeRenderer; +use crate::platform::blade::{BladeContext, BladeRenderer}; use crate::*; pub(crate) struct WindowsWindow(pub Rc); @@ -78,6 +78,7 @@ impl WindowsWindowState { cs: &CREATESTRUCTW, current_cursor: HCURSOR, display: WindowsDisplay, + gpu_context: &BladeContext, ) -> Result { let scale_factor = { let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32; @@ -94,7 +95,7 @@ impl WindowsWindowState { }; let border_offset = WindowBorderOffset::default(); let is_minimized = None; - let renderer = windows_renderer::windows_renderer(hwnd, transparent)?; + let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?; let callbacks = Callbacks::default(); let input_handler = None; let system_key_handled = false; @@ -227,6 +228,7 @@ impl WindowsWindowStatePtr { cs, context.current_cursor, context.display, + context.gpu_context, )?); Ok(Rc::new_cyclic(|this| Self { @@ -340,7 +342,7 @@ pub(crate) struct Callbacks { pub(crate) appearance_changed: Option>, } -struct WindowCreateContext { +struct WindowCreateContext<'a> { inner: Option>>, handle: AnyWindowHandle, hide_title_bar: bool, @@ -352,6 +354,7 @@ struct WindowCreateContext { windows_version: WindowsVersion, validation_number: usize, main_receiver: flume::Receiver, + gpu_context: &'a BladeContext, } impl WindowsWindow { @@ -359,6 +362,7 @@ impl WindowsWindow { handle: AnyWindowHandle, params: WindowParams, creation_info: WindowCreationInfo, + gpu_context: &BladeContext, ) -> Result { let WindowCreationInfo { icon, @@ -410,6 +414,7 @@ impl WindowsWindow { windows_version, validation_number, main_receiver, + gpu_context, }; let lpparam = Some(&context as *const _ as *const _); let creation_result = unsafe { @@ -1236,38 +1241,24 @@ fn set_window_composition_attribute(hwnd: HWND, color: Option, state: u32 } mod windows_renderer { - use std::{num::NonZeroIsize, sync::Arc}; - - use blade_graphics as gpu; + use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}; use raw_window_handle as rwh; + use std::num::NonZeroIsize; use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::GWLP_HINSTANCE}; - use crate::{ - get_window_long, - platform::blade::{BladeRenderer, BladeSurfaceConfig}, - }; + use crate::get_window_long; - pub(super) fn windows_renderer(hwnd: HWND, transparent: bool) -> anyhow::Result { + pub(super) fn init( + context: &BladeContext, + hwnd: HWND, + transparent: bool, + ) -> anyhow::Result { let raw = RawWindow { hwnd }; - let gpu: Arc = Arc::new( - unsafe { - gpu::Context::init_windowed( - &raw, - gpu::ContextDesc { - validation: false, - capture: false, - overlay: false, - }, - ) - } - .map_err(|e| anyhow::anyhow!("{:?}", e))?, - ); let config = BladeSurfaceConfig { - size: gpu::Extent::default(), + size: Default::default(), transparent, }; - - Ok(BladeRenderer::new(gpu, config)) + BladeRenderer::new(context, &raw, config) } struct RawWindow { diff --git a/crates/media/Cargo.toml b/crates/media/Cargo.toml index 70478eeb759f8..1f2cfb085461a 100644 --- a/crates/media/Cargo.toml +++ b/crates/media/Cargo.toml @@ -19,7 +19,7 @@ anyhow.workspace = true core-foundation.workspace = true ctor.workspace = true foreign-types = "0.5" -metal = "0.29" +metal.workspace = true objc = "0.2" [build-dependencies]