Change summary
crates/gpui/Cargo.toml | 9 ++++++
crates/gpui/build.rs | 25 ++++++++++++++++++-
crates/gpui/src/platform/mac/metal_renderer.rs | 10 +++++++
3 files changed, 40 insertions(+), 4 deletions(-)
Detailed changes
@@ -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"
@@ -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<PathBuf> {
+ 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")
@@ -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");