From d3cd12aa475b4063edf7c9be703062a813d67678 Mon Sep 17 00:00:00 2001 From: colin Date: Tue, 5 Jul 2022 16:37:00 -0700 Subject: [PATCH] split the spirv builder out of the runtime spirv executable this means that we unconditionally build the spirv runner, and hence it requires that the user setup the proper rustc toolchain, etc. may want to hide this behind a feature flag. --- Cargo.lock | 5 ++ Cargo.toml | 1 + src/sim/spirv/mod.rs | 42 +++-------- .../spirv/spirv_backend_builder/Cargo.toml | 9 +++ .../spirv/spirv_backend_builder/src/main.rs | 30 ++++++++ src/sim/spirv/spirv_backend_runner/Cargo.toml | 8 +++ src/sim/spirv/spirv_backend_runner/build.rs | 69 +++++++++++++++++++ src/sim/spirv/spirv_backend_runner/src/lib.rs | 8 +++ 8 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 src/sim/spirv/spirv_backend_builder/Cargo.toml create mode 100644 src/sim/spirv/spirv_backend_builder/src/main.rs create mode 100644 src/sim/spirv/spirv_backend_runner/Cargo.toml create mode 100644 src/sim/spirv/spirv_backend_runner/build.rs create mode 100644 src/sim/spirv/spirv_backend_runner/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c82e3eb..dae23be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,6 +328,7 @@ dependencies = [ "spirv-std", "spirv-std-macros", "spirv_backend_lib", + "spirv_backend_runner", "structopt", "threadpool", "typetag", @@ -2037,6 +2038,10 @@ dependencies = [ "spirv-std", ] +[[package]] +name = "spirv_backend_runner" +version = "0.1.0" + [[package]] name = "strsim" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 5f72703..7d6c481 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ spirv-builder = { git = "https://github.com/EmbarkStudios/rust-gpu", features = spirv-std = { git = "https://github.com/EmbarkStudios/rust-gpu" } spirv-std-macros = { git = "https://github.com/EmbarkStudios/rust-gpu" } spirv_backend_lib = { path = "src/sim/spirv/spirv_backend_lib" } +spirv_backend_runner = { path = "src/sim/spirv/spirv_backend_runner" } [dev-dependencies] diff --git a/src/sim/spirv/mod.rs b/src/sim/spirv/mod.rs index 01b605f..fcd4c34 100644 --- a/src/sim/spirv/mod.rs +++ b/src/sim/spirv/mod.rs @@ -1,15 +1,13 @@ use futures::FutureExt as _; -use log::trace; use ndarray::{self, Array3}; use serde::{Deserialize, Serialize}; -use spirv_builder::{Capability, MetadataPrintout, SpirvBuilder}; use std::borrow::Cow; use std::num::NonZeroU64; use std::path::PathBuf; use std::sync::Arc; use wgpu; use wgpu::util::DeviceExt as _; -use log::{info, warn}; +use log::{info, trace, warn}; use crate::geom::{Coord, Index, Meters, Vec3}; use crate::real::Real as _; @@ -51,6 +49,7 @@ impl WgpuData { pub fn new(volume: u64) -> Self where M::Ffi: 'static { + info!("WgpuData::new({})", volume); use std::mem::size_of; let max_elem_size = size_of::().max(size_of::>()); let max_buf_size = volume * max_elem_size as u64 + 0x1000; @@ -489,37 +488,9 @@ unsafe fn from_bytes(slice: &[u8]) -> &[T] { std::slice::from_raw_parts(slice.as_ptr() as *const T, new_len) } -/// Compiles the compute shader to spirv +/// Loads the shader fn get_shader() -> wgpu::ShaderModuleDescriptorSpirV<'static> { - // based on rust-gpu/examples/runners/wgpu/src/lib.rs:maybe_watch - // Hack: spirv_builder builds into a custom directory if running under cargo, to not - // deadlock, and the default target directory if not. However, packages like `proc-macro2` - // have different configurations when being built here vs. when building - // rustc_codegen_spirv normally, so we *want* to build into a separate target directory, to - // not have to rebuild half the crate graph every time we run. So, pretend we're running - // under cargo by setting these environment variables. - // std::env::set_var("OUT_DIR", env!("OUT_DIR")); - // std::env::set_var("PROFILE", env!("PROFILE")); - // Capabilities documented here: https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Capability - let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let crate_path = [manifest_dir, "src", "sim", "spirv", "spirv_backend"] - .iter() - .copied() - .collect::(); - let builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1") - //let builder = SpirvBuilder::new(crate_path, "spirv-unknown-spv1.3") - .print_metadata(MetadataPrintout::None) - .capability(Capability::Int8) - // .capability(Capability::PhysicalStorageBufferAddresses) - // .capability(Capability::Addresses) - // .capability(Capability::GenericPointer) - ; - - let initial_result = builder.build().unwrap(); - - let module_path = initial_result.module.unwrap_single(); - let data = std::fs::read(module_path.clone()).unwrap_or_else(|e| { panic!("module path: {:?}: {:?}", module_path, e) }); - + let data = spirv_backend_runner::spirv_module(); let spirv = Cow::Owned(wgpu::util::make_spirv_raw(&data).into_owned()); wgpu::ShaderModuleDescriptorSpirV { @@ -531,14 +502,16 @@ fn get_shader() -> wgpu::ShaderModuleDescriptorSpirV<'static> { async fn open_device(max_buf_size: u64) -> (wgpu::Device, wgpu::Queue) { // based on rust-gpu/examples/runners/wgpu/src/compute.rs:start_internal let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); + info!("open_device: got instance"); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::default(), + power_preference: wgpu::PowerPreference::HighPerformance, force_fallback_adapter: false, compatible_surface: None, }) .await .expect("Failed to find an appropriate adapter"); + info!("open_device: got adapter"); // XXX not all adapters will support non-default limits, and it could // cause perf degradations even on the ones that do. May want to consider @@ -562,6 +535,7 @@ async fn open_device(max_buf_size: u64) -> (wgpu::Device, wgpu::Queue) { ) .await .expect("Failed to create device"); + info!("open_device: got device"); (device, queue) } diff --git a/src/sim/spirv/spirv_backend_builder/Cargo.toml b/src/sim/spirv/spirv_backend_builder/Cargo.toml new file mode 100644 index 0000000..fa57751 --- /dev/null +++ b/src/sim/spirv/spirv_backend_builder/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "spirv_backend_builder" +version = "0.1.0" +authors = ["Colin "] +edition = "2021" + +[dependencies] +log = "0.4" +spirv-builder = { git = "https://github.com/EmbarkStudios/rust-gpu", features = ["use-compiled-tools"] } diff --git a/src/sim/spirv/spirv_backend_builder/src/main.rs b/src/sim/spirv/spirv_backend_builder/src/main.rs new file mode 100644 index 0000000..227157a --- /dev/null +++ b/src/sim/spirv/spirv_backend_builder/src/main.rs @@ -0,0 +1,30 @@ +use spirv_builder::{Capability, MetadataPrintout, SpirvBuilder}; +use log::info; +use std::env; +use std::error::Error; +use std::path::PathBuf; + +fn main() -> Result<(), Box> { + // based on EmbarkStudios/rust-gpu/examples/runners/wgpu/src/lib.rs:maybe_watch + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let crate_path = [manifest_dir, "../", "spirv_backend"] + .iter() + .copied() + .collect::(); + info!("get_shader: constructing builder"); + let builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1") + //let builder = SpirvBuilder::new(crate_path, "spirv-unknown-spv1.3") + .print_metadata(MetadataPrintout::None) + .capability(Capability::Int8) + // .capability(Capability::PhysicalStorageBufferAddresses) + // .capability(Capability::Addresses) + // .capability(Capability::GenericPointer) + ; + + info!("get_shader: building"); + let initial_result = builder.build()?; + + let module_path = initial_result.module.unwrap_single(); + info!("get_shader: built: {:?}", module_path); + Ok(()) +} diff --git a/src/sim/spirv/spirv_backend_runner/Cargo.toml b/src/sim/spirv/spirv_backend_runner/Cargo.toml new file mode 100644 index 0000000..343b635 --- /dev/null +++ b/src/sim/spirv/spirv_backend_runner/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "spirv_backend_runner" +version = "0.1.0" +authors = ["Colin "] +edition = "2021" + +[lib] +crate-type = ["lib"] diff --git a/src/sim/spirv/spirv_backend_runner/build.rs b/src/sim/spirv/spirv_backend_runner/build.rs new file mode 100644 index 0000000..cfd6f83 --- /dev/null +++ b/src/sim/spirv/spirv_backend_runner/build.rs @@ -0,0 +1,69 @@ +use std::env; +use std::error::Error; +use std::path::PathBuf; + +fn main() -> Result<(), Box> { + // heavily inspired from EmbarkStudios/rust-gpu/examples/runners/wgpu/build.rs + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ARCH"); + // While OUT_DIR is set for both build.rs and compiling the crate, PROFILE is only set in + // build.rs. So, export it to crate compilation as well. + let profile = env::var("PROFILE").unwrap(); + println!("cargo:rustc-env=PROFILE={}", profile); + let mut dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + // recover the directory from which this was invoked + assert!( + dir.ends_with("out") + && dir.pop() + && dir.pop() + && dir.ends_with("build") + && dir.pop() + && dir.ends_with(profile) + && dir.pop() + ); + + // recover the toplevel directory + assert!( + dir.ends_with("target") + && dir.pop() + ); + if dir.ends_with("spirv_backend_runner") { + // being run from this dir + assert!( + dir.pop() + && dir.ends_with("spirv") + && dir.pop() + && dir.ends_with("sim") + && dir.pop() + && dir.ends_with("src") + && dir.pop() + ); + } // else already at the top-level dir + + let target_dir = dir.join("target/spirv_backend_builder"); + let manifest_path = dir.join("src/sim/spirv/spirv_backend_builder/Cargo.toml"); + println!("target_dir: {:?}", target_dir); + println!("manifest_path: {:?}", manifest_path); + + let status = std::process::Command::new("cargo") + .args([ + "run", + "--release", + "--manifest-path", + ]) + .arg(manifest_path) + .arg("--target-dir") + .arg(target_dir) + .stderr(std::process::Stdio::inherit()) + .stdout(std::process::Stdio::inherit()) + .status()?; + if !status.success() { + if let Some(code) = status.code() { + std::process::exit(code); + } else { + std::process::exit(1); + } + } + Ok(()) +} diff --git a/src/sim/spirv/spirv_backend_runner/src/lib.rs b/src/sim/spirv/spirv_backend_runner/src/lib.rs new file mode 100644 index 0000000..2889b6f --- /dev/null +++ b/src/sim/spirv/spirv_backend_runner/src/lib.rs @@ -0,0 +1,8 @@ +/// returns the compiled spirv module +/// for use with e.g. `wgpu::util::make_spirv_raw`. +pub fn spirv_module() -> &'static [u8] { + // we specifically include the bytes into this binary, for ease of packaging (v.s. attempting + // to locate the compiled result at runtime). + include_bytes!("../../../../../target/spirv-builder/spirv-unknown-vulkan1.1/release/deps/spirv_backend.spv.dir/module") +} +