Files
Sunscreen/sunscreen_math/build.rs
rickwebiii 06e9c1cb2b Rweber/opencl (#230)
OpenCL implementation of curve25519 operations
2023-03-22 14:30:45 -07:00

218 lines
6.3 KiB
Rust

#[cfg(feature = "opencl")]
fn compile_opencl_shaders() {
use std::ffi::CString;
use ocl::{Context, Device, Platform, Program};
const KERNEL_SOURCE: &str = include_str!("src/opencl_impl/shaders/sunscreen_math.cl");
let platform = Platform::first().unwrap();
let device = Device::first(platform).unwrap();
let ctx = Context::builder().devices(device).build().unwrap();
// Assert we can compile our program and print any errors if not.
let program = Program::with_source(
&ctx,
&[CString::new(KERNEL_SOURCE).unwrap()],
Some(&[device]),
&CString::new("-DTEST").unwrap(),
);
match program {
Ok(_) => {}
Err(e) => {
println!("{}", e);
panic!();
}
}
}
#[cfg(feature = "webgpu")]
// This simply concatenates all the wgsl shaders, which get compiled at runtime.
fn compile_wgsl_shaders() {
use std::fs::{read_to_string, DirEntry, File};
use std::io::Write;
use std::path::PathBuf;
use naga::valid::{Capabilities, ValidationFlags};
use wgpu_core::pipeline::{CreateShaderModuleError, ShaderError};
let outdir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let shader_dir = PathBuf::from(".")
.join("src")
.join("webgpu_impl")
.join("shaders");
for config in ["test", "release"] {
let is_wgsl_file = |file: &DirEntry| {
file.file_name().to_string_lossy().ends_with(".wgsl")
&& file.file_type().unwrap().is_file()
};
let is_test_wgsl_file = |file: &DirEntry| {
file.file_name().to_string_lossy().ends_with(".test.wgsl")
&& file.file_type().unwrap().is_file()
};
let include_file: Box<dyn Fn(&DirEntry) -> bool> = if config == "test" {
Box::new(is_wgsl_file)
} else {
Box::new(|file: &DirEntry| is_wgsl_file(file) && !is_test_wgsl_file(file))
};
let shaders = std::fs::read_dir(&shader_dir)
.unwrap()
.filter_map(Result::ok)
.filter(include_file);
let out_file_path = outdir.join(format!("shaders-{config}.wgsl"));
{
let mut out_file = File::create(&out_file_path).unwrap();
for s in shaders {
let data = read_to_string(s.path()).unwrap();
writeln!(out_file, "{}", data).unwrap();
}
};
// Validate the shader
let shader_contents = read_to_string(&out_file_path).unwrap();
let parse_result = naga::front::wgsl::parse_str(&shader_contents);
if let Err(e) = parse_result {
let e = ShaderError {
source: shader_contents,
label: None,
inner: Box::new(e),
};
let e = CreateShaderModuleError::Parsing(e);
panic!("{}", e);
}
let mut validator =
naga::valid::Validator::new(ValidationFlags::all(), Capabilities::empty());
let validation_results = validator.validate(&parse_result.unwrap());
if let Err(e) = validation_results {
let e = ShaderError {
source: shader_contents,
label: None,
inner: Box::new(e),
};
let e = CreateShaderModuleError::Validation(e);
panic!("{}", e.to_string());
}
}
}
#[cfg(feature = "metal")]
fn compile_metal_shaders() {
use std::{path::PathBuf, process::Command};
let outdir = std::env::var("OUT_DIR").unwrap();
let shader_dir = PathBuf::from(".")
.join("src")
.join("metal_impl")
.join("shaders");
println!("cargo:rerun-if-changed=src/metal_impl/shaders");
let include_dir = shader_dir.join("include");
for config in ["test", "release"] {
let mut air_files = vec![];
let is_metal_file = |file: &std::fs::DirEntry| {
file.file_name().to_string_lossy().ends_with(".metal")
&& file.file_type().unwrap().is_file()
};
let shaders = std::fs::read_dir(&shader_dir)
.unwrap()
.filter_map(Result::ok)
.filter(is_metal_file);
for file in shaders {
let filename = file.file_name().to_string_lossy().into_owned();
let out_name = if !file.file_name().to_string_lossy().ends_with(".metal")
|| !file.file_type().unwrap().is_file()
{
continue;
} else {
format!("{}.air", filename.strip_suffix(".metal").unwrap())
};
let outfile = PathBuf::from(&outdir).join(&out_name);
air_files.push(outfile.clone());
let output = Command::new("xcrun")
.arg("-sdk")
.arg("macosx")
.arg("metal")
.arg("-g")
.arg("-Wall")
.arg("-Werror")
.arg(format!("-D{}", config.to_uppercase()))
.arg("-c")
.arg(file.path())
.arg("-I")
.arg(&include_dir)
.arg("-o")
.arg(outfile)
.output()
.unwrap();
if !output.status.success() {
println!("===stderr===");
println!("{}", String::from_utf8_lossy(&output.stderr));
println!("===stdout===");
println!("{}", String::from_utf8_lossy(&output.stdout));
panic!("Shader compilation failed.");
}
}
let libout = PathBuf::from(&outdir).join(format!("curve25519-dalek.{config}.metallib"));
let output = Command::new("xcrun")
.arg("-sdk")
.arg("macosx")
.arg("metallib")
.args(air_files)
.arg("-o")
.arg(libout)
.output()
.unwrap();
if !output.status.success() {
println!("===stderr===");
println!("{}", String::from_utf8_lossy(&output.stderr));
println!("===stdout===");
println!("{}", String::from_utf8_lossy(&output.stdout));
panic!("Shader compilation failed.");
}
}
}
fn main() {
#[cfg(feature = "metal")]
compile_metal_shaders();
#[cfg(feature = "webgpu")]
compile_wgsl_shaders();
#[cfg(feature = "opencl")]
compile_opencl_shaders();
}