Skip to content

Commit

Permalink
[official] Linux port via Blade (#7343)
Browse files Browse the repository at this point in the history
## Motivation

I ❤️ Zed! It's lightning fast and has great UX. I want it to run as
well on all major platforms. I'm currently using Linux most actively.
[Blade](https://github.com/kvark/blade) is a good candidate for
providing GPU access: it supports Vulkan, Metal, and GLES/WebGL. Its
abstraction is extremely thin, while having one of the nicest GPU APIs.
Codebase is also tiny. Checkout [the meetup
recording](https://www.youtube.com/watch?v=63dnzjw4azI&t=623s) from a
year ago.
I believe these projects make a good match 🚀 !

### Why this is a bad idea

If Zed team wants to use off-the-shelf components from Rust ecosystem,
then Blade is certainly at disadvantage here, since it's not widely
used. It would rely on Zed team adding necessary features in a branch,
then maybe upstreaming some of them. That is to say, it's unclear if
this can be avoided with more popular alternatives - being flexible with
any local changes is a good ability.

### Why it's not too bad

Blade uses [WGSL](https://www.w3.org/TR/WGSL) shaders, similar to `wgpu`
and `arcana`, but without the binding decorations. So this aspect of the
product is nicely portable.

## Progress

- [ ] Platforms
  - [x] X11 (via xcb)
    - [ ] input handling
    - [ ] get proper content size
  - [ ] Windows
  - [ ] Replace the existing Metal backend
- [ ] Text System
  - [ ] shaping
  - [ ] glyph rasterization
- [x] Texture atlas
- [ ] Rendering
  - [x] basic primitives
  - [x] path rendering
  - [x] sprite rendering
- [ ] media surfaces
- [ ] CI

## Current status
Zed starts up but crashes on text-system related checks.

![zed-linux-1](https://github.com/zed-industries/zed/assets/107301/ba536218-4d2c-43c9-ae6c-bef69b54bd0c)
  • Loading branch information
mikayla-maki committed Feb 7, 2024
2 parents 6edeea7 + 3a53db6 commit 5ded865
Show file tree
Hide file tree
Showing 38 changed files with 3,188 additions and 67 deletions.
274 changes: 268 additions & 6 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.
split-debuginfo = "unpacked"
debug = "limited"

# todo!(linux) - Remove this
[profile.dev.package.blade-graphics]
split-debuginfo = "off"
debug = "full"

[profile.dev.package.taffy]
opt-level = 3

Expand Down
7 changes: 6 additions & 1 deletion crates/fs/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,17 @@ impl Fs for RealFs {
) -> Pin<Box<dyn Send + Stream<Item = Vec<Event>>>> {
let (tx, rx) = smol::channel::unbounded();

if !path.exists() {
log::error!("watch path does not exist: {}", path.display());
return Box::pin(rx);
}

let mut watcher = notify::recommended_watcher(move |res| match res {
Ok(event) => {
let _ = tx.try_send(vec![event]);
}
Err(err) => {
eprintln!("watch error: {:?}", err);
log::error!("watch error: {}", err);
}
})
.unwrap();
Expand Down
14 changes: 12 additions & 2 deletions crates/gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dhat = { version = "0.3", optional = true }
env_logger = { version = "0.9", optional = true }
etagere = "0.2"
futures.workspace = true
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "d97147f" }
gpui_macros.workspace = true
image = "0.23"
itertools = "0.10"
Expand All @@ -46,7 +47,8 @@ parking_lot.workspace = true
pathfinder_geometry = "0.5"
postage.workspace = true
rand.workspace = true
raw-window-handle = "0.6.0"
raw-window-handle = "0.6"
blade-rwh = { package = "raw-window-handle", version = "0.5" }
refineable.workspace = true
resvg = "0.14"
schemars.workspace = true
Expand Down Expand Up @@ -86,9 +88,17 @@ cocoa = "0.25"
core-foundation = { version = "0.9.3", features = ["with-uuid"] }
core-graphics = "0.22.3"
core-text = "19.2"
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "d97147f" }
foreign-types = "0.3"
log.workspace = true
media.workspace = true
metal = "0.21.0"
objc = "0.2"

[target.'cfg(target_os = "linux")'.dependencies]
flume = "0.11"
xcb = { version = "1.3", features = ["as-raw-xcb-connection"] }
as-raw-xcb-connection = "1"
#TODO: use these on all platforms
blade-graphics = { git = "https://github.com/kvark/blade", rev = "f35bc605154e210ab6190291235889b6ddad73f1" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "f35bc605154e210ab6190291235889b6ddad73f1" }
bytemuck = "1"
6 changes: 6 additions & 0 deletions crates/gpui/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg_attr(not(target_os = "macos"), allow(unused))]

use std::{
env,
path::{Path, PathBuf},
Expand All @@ -6,10 +8,14 @@ use std::{
use cbindgen::Config;

fn main() {
#[cfg(target_os = "macos")]
generate_dispatch_bindings();
#[cfg(target_os = "macos")]
let header_path = generate_shader_bindings();
#[cfg(target_os = "macos")]
#[cfg(feature = "runtime_shaders")]
emit_stitched_shaders(&header_path);
#[cfg(target_os = "macos")]
#[cfg(not(feature = "runtime_shaders"))]
compile_metal_shaders(&header_path);
}
Expand Down
5 changes: 4 additions & 1 deletion crates/gpui/examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ impl Render for HelloWorld {
div()
.flex()
.bg(rgb(0x2e7d32))
.size_full()
.size(Length::Definite(Pixels(300.0).into()))
.justify_center()
.items_center()
.shadow_lg()
.border()
.border_color(rgb(0x0000ff))
.text_xl()
.text_color(rgb(0xffffff))
.child(format!("Hello, {}!", &self.text))
Expand Down
4 changes: 4 additions & 0 deletions crates/gpui/src/elements/img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
StyleRefinement, Styled, UriOrPath,
};
use futures::FutureExt;
#[cfg(target_os = "macos")]
use media::core_video::CVImageBuffer;
use util::ResultExt;

Expand All @@ -21,6 +22,7 @@ pub enum ImageSource {
Data(Arc<ImageData>),
// TODO: move surface definitions into mac platform module
/// A CoreVideo image buffer
#[cfg(target_os = "macos")]
Surface(CVImageBuffer),
}

Expand Down Expand Up @@ -54,6 +56,7 @@ impl From<Arc<ImageData>> for ImageSource {
}
}

#[cfg(target_os = "macos")]
impl From<CVImageBuffer> for ImageSource {
fn from(value: CVImageBuffer) -> Self {
Self::Surface(value)
Expand Down Expand Up @@ -144,6 +147,7 @@ impl Element for Img {
.log_err();
}

#[cfg(target_os = "macos")]
ImageSource::Surface(surface) => {
let size = size(surface.width().into(), surface.height().into());
let new_bounds = preserve_aspect_ratio(bounds, size);
Expand Down
3 changes: 1 addition & 2 deletions crates/gpui/src/gpui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
//! ## Getting Started
//!
//! GPUI is still in active development as we work on the Zed code editor and isn't yet on crates.io.
//! You'll also need to use the latest version of stable rust and be on macOS. Add the following to your
//! Cargo.toml:
//! You'll also need to use the latest version of stable rust. Add the following to your Cargo.toml:
//!
//! ```
//! gpui = { git = "https://github.com/zed-industries/zed" }
Expand Down
9 changes: 9 additions & 0 deletions crates/gpui/src/platform.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod app_menu;
mod keystroke;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod mac;
#[cfg(any(test, feature = "test-support"))]
Expand Down Expand Up @@ -33,6 +35,8 @@ use uuid::Uuid;

pub use app_menu::*;
pub use keystroke::*;
#[cfg(target_os = "linux")]
pub(crate) use linux::*;
#[cfg(target_os = "macos")]
pub(crate) use mac::*;
#[cfg(any(test, feature = "test-support"))]
Expand All @@ -44,6 +48,10 @@ pub use util::SemanticVersion;
pub(crate) fn current_platform() -> Rc<dyn Platform> {
Rc::new(MacPlatform::new())
}
#[cfg(target_os = "linux")]
pub(crate) fn current_platform() -> Rc<dyn Platform> {
Rc::new(LinuxPlatform::new())
}

pub(crate) trait Platform: 'static {
fn background_executor(&self) -> BackgroundExecutor;
Expand Down Expand Up @@ -298,6 +306,7 @@ pub(crate) trait PlatformAtlas: Send + Sync {
pub(crate) struct AtlasTile {
pub(crate) texture_id: AtlasTextureId,
pub(crate) tile_id: TileId,
pub(crate) padding: u32,
pub(crate) bounds: Bounds<DevicePixels>,
}

Expand Down
18 changes: 18 additions & 0 deletions crates/gpui/src/platform/linux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
mod blade_atlas;
mod blade_belt;
mod blade_renderer;
mod dispatcher;
mod display;
mod platform;
mod text_system;
mod window;

pub(crate) use blade_atlas::*;
pub(crate) use dispatcher::*;
pub(crate) use display::*;
pub(crate) use platform::*;
pub(crate) use text_system::*;
pub(crate) use window::*;

use blade_belt::*;
use blade_renderer::*;
Loading

0 comments on commit 5ded865

Please sign in to comment.