From 5941102aac43643a509516f67bc9730f1d6185ed Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:37:16 +0100 Subject: [PATCH] gpui: Add runtime-shaders feature so that Xcode.app is no longer necessary for Nix-based workflows (#7148) Release Notes: - N/A Co-authored-by: Niklas --- crates/gpui/Cargo.toml | 9 ++++++- crates/gpui/build.rs | 25 +++++++++++++++++-- .../gpui/src/platform/mac/metal_renderer.rs | 10 +++++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 0bc28b8db4..96c7b4b02c 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -8,7 +8,14 @@ publish = false license = "Apache-2.0" [features] -test-support = ["backtrace", "dhat", "env_logger", "collections/test-support", "util/test-support"] +test-support = [ + "backtrace", + "dhat", + "env_logger", + "collections/test-support", + "util/test-support", +] +runtime_shaders = [] [lib] path = "src/gpui.rs" diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index b237583847..4c86fe9a62 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -1,7 +1,6 @@ use std::{ env, path::{Path, PathBuf}, - process::{self, Command}, }; use cbindgen::Config; @@ -9,6 +8,9 @@ use cbindgen::Config; fn main() { generate_dispatch_bindings(); let header_path = generate_shader_bindings(); + #[cfg(feature = "runtime_shaders")] + emit_stitched_shaders(&header_path); + #[cfg(not(feature = "runtime_shaders"))] compile_metal_shaders(&header_path); } @@ -95,11 +97,30 @@ fn generate_shader_bindings() -> PathBuf { output_path } +/// To enable runtime compilation, we need to "stitch" the shaders file with the generated header +/// so that it is self-contained. +#[cfg(feature = "runtime_shaders")] +fn emit_stitched_shaders(header_path: &Path) { + use std::str::FromStr; + fn stitch_header(header: &Path, shader_path: &Path) -> std::io::Result { + let header_contents = std::fs::read_to_string(header)?; + let shader_contents = std::fs::read_to_string(shader_path)?; + let stitched_contents = format!("{header_contents}\n{shader_contents}"); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("stitched_shaders.metal"); + let _ = std::fs::write(&out_path, stitched_contents)?; + Ok(out_path) + } + let shader_source_path = "./src/platform/mac/shaders.metal"; + let shader_path = PathBuf::from_str(shader_source_path).unwrap(); + stitch_header(header_path, &shader_path).unwrap(); + println!("cargo:rerun-if-changed={}", &shader_source_path); +} +#[cfg(not(feature = "runtime_shaders"))] fn compile_metal_shaders(header_path: &Path) { + use std::process::{self, Command}; let shader_path = "./src/platform/mac/shaders.metal"; let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air"); let metallib_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib"); - println!("cargo:rerun-if-changed={}", shader_path); let output = Command::new("xcrun") diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 1589757d93..68027ceff6 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -17,7 +17,11 @@ use objc::{self, msg_send, sel, sel_impl}; use smallvec::SmallVec; use std::{ffi::c_void, mem, ptr, sync::Arc}; +#[cfg(not(feature = "runtime_shaders"))] const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); +#[cfg(feature = "runtime_shaders")] +const SHADERS_SOURCE_FILE: &'static str = + include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal")); const INSTANCE_BUFFER_SIZE: usize = 32 * 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value (maybe even we could adjust dynamically...) pub(crate) struct MetalRenderer { @@ -60,7 +64,11 @@ impl MetalRenderer { | AutoresizingMask::HEIGHT_SIZABLE ]; } - + #[cfg(feature = "runtime_shaders")] + let library = device + .new_library_with_source(&SHADERS_SOURCE_FILE, &metal::CompileOptions::new()) + .expect("error building metal library"); + #[cfg(not(feature = "runtime_shaders"))] let library = device .new_library_with_data(SHADERS_METALLIB) .expect("error building metal library");