Add support for outputting multiple modules, one per entry point (#551)

* Add multimodule feature

* Use -Cllvm-args instead of -Ctarget-feature for multimodule

* Fix cargo.toml
This commit is contained in:
Ashley Hauck 2021-03-29 17:59:03 +02:00 committed by GitHub
parent 30c9b1fdc0
commit c3a3b20e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 274 additions and 144 deletions

149
Cargo.lock generated
View File

@ -1402,9 +1402,9 @@ dependencies = [
[[package]]
name = "memoffset"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
checksum = "cc14fc54a812b4472b4113facc3e44d099fbc0ea2ce0551fa5c703f8edfbfd38"
dependencies = [
"autocfg",
]
@ -1425,17 +1425,17 @@ dependencies = [
[[package]]
name = "minifb"
version = "0.19.2"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87b4b6a6da61c3003a41e84ee1f6b56e079f835f4d4fce424fc84092b57ad804"
checksum = "7b6e41119d1667465608d36488fa5dcd228057a26c156e25f17f492f38435124"
dependencies = [
"cc",
"orbclient",
"raw-window-handle",
"tempfile",
"wayland-client 0.27.0",
"wayland-cursor 0.27.0",
"wayland-protocols 0.27.0",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
"winapi 0.3.9",
"x11-dl",
"xkb",
@ -1513,6 +1513,13 @@ dependencies = [
"spirv-std",
]
[[package]]
name = "multibuilder"
version = "0.1.0"
dependencies = [
"spirv-builder",
]
[[package]]
name = "naga"
version = "0.3.2"
@ -1585,19 +1592,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "nix"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags",
"cc",
"cfg-if 0.1.10",
"libc",
"void",
]
[[package]]
name = "nix"
version = "0.18.0"
@ -2110,6 +2104,7 @@ dependencies = [
"pretty_assertions",
"rspirv",
"rustc-demangle",
"sanitize-filename",
"serde",
"serde_json",
"smallvec",
@ -2169,6 +2164,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "sanitize-filename"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf18934a12018228c5b55a6dae9df5d0641e3566b3630cb46cc55564068e7c2f"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -2314,9 +2319,9 @@ dependencies = [
"log",
"memmap2",
"nix 0.18.0",
"wayland-client 0.28.5",
"wayland-cursor 0.28.5",
"wayland-protocols 0.28.5",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
@ -2758,17 +2763,11 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "walkdir"
version = "2.3.1"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi 0.3.9",
@ -2847,21 +2846,6 @@ version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
[[package]]
name = "wayland-client"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab702fefbcd6d6f67fb5816e3a89a3b5a42a94290abbc015311c9a30d1068ae4"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.17.0",
"wayland-commons 0.27.0",
"wayland-scanner 0.27.0",
"wayland-sys 0.27.0",
]
[[package]]
name = "wayland-client"
version = "0.28.5"
@ -2873,21 +2857,9 @@ dependencies = [
"libc",
"nix 0.20.0",
"scoped-tls",
"wayland-commons 0.28.5",
"wayland-scanner 0.28.5",
"wayland-sys 0.28.5",
]
[[package]]
name = "wayland-commons"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e972e9336ad5a9dd861b4e21ff35ad71d3e5c6b4803d65c39913612f851b95f1"
dependencies = [
"nix 0.17.0",
"once_cell",
"smallvec",
"wayland-sys 0.27.0",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
@ -2899,18 +2871,7 @@ dependencies = [
"nix 0.20.0",
"once_cell",
"smallvec",
"wayland-sys 0.28.5",
]
[[package]]
name = "wayland-cursor"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "539f346e1a3f706f38c8ccbe1196001e2fb1c9b3e6b605c27d665db2f5b60d41"
dependencies = [
"nix 0.17.0",
"wayland-client 0.27.0",
"xcursor",
"wayland-sys",
]
[[package]]
@ -2920,22 +2881,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab"
dependencies = [
"nix 0.20.0",
"wayland-client 0.28.5",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d6fc54b17b98b5083bc21ae3a30e6d75cb4b01647360e4c3a04648bcf8781d"
dependencies = [
"bitflags",
"wayland-client 0.27.0",
"wayland-commons 0.27.0",
"wayland-scanner 0.27.0",
]
[[package]]
name = "wayland-protocols"
version = "0.28.5"
@ -2943,20 +2892,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c"
dependencies = [
"bitflags",
"wayland-client 0.28.5",
"wayland-commons 0.28.5",
"wayland-scanner 0.28.5",
]
[[package]]
name = "wayland-scanner"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030f56009d932bd9400bb472764fea8109be1b0fc482d9cd75496c943ac30328"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
@ -2970,15 +2908,6 @@ dependencies = [
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bdeffbbb474477dfa2acb45ac7479e5fe8f741c64ab032c5d11b94d07edc269"
dependencies = [
"pkg-config",
]
[[package]]
name = "wayland-sys"
version = "0.28.5"
@ -3150,7 +3079,7 @@ dependencies = [
"raw-window-handle",
"smithay-client-toolkit",
"wasm-bindgen",
"wayland-client 0.28.5",
"wayland-client",
"web-sys",
"winapi 0.3.9",
"x11-dl",

View File

@ -7,6 +7,7 @@ members = [
"examples/shaders/simplest-shader",
"examples/shaders/compute-shader",
"examples/shaders/mouse-shader",
"examples/multibuilder",
"crates/rustc_codegen_spirv",
"crates/spirv-builder",

View File

@ -39,6 +39,7 @@ bimap = "0.6"
indexmap = "1.6.0"
rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "ee1e913" }
rustc-demangle = "0.1.18"
sanitize-filename = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smallvec = "1.6.1"

View File

@ -33,6 +33,7 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::iter::once;
use std::rc::Rc;
use std::str::FromStr;
pub struct CodegenCx<'tcx> {
pub tcx: TyCtxt<'tcx>,
@ -69,6 +70,8 @@ pub struct CodegenCx<'tcx> {
/// Some runtimes (e.g. intel-compute-runtime) disallow atomics on i8 and i16, even though it's allowed by the spec.
/// This enables/disables them.
pub i8_i16_atomics_allowed: bool,
pub codegen_args: CodegenArgs,
}
impl<'tcx> CodegenCx<'tcx> {
@ -102,6 +105,7 @@ impl<'tcx> CodegenCx<'tcx> {
tcx.sess.err(&format!("Unknown feature {}", feature));
}
}
let codegen_args = CodegenArgs::from_session(tcx.sess);
Self {
tcx,
codegen_unit,
@ -120,6 +124,7 @@ impl<'tcx> CodegenCx<'tcx> {
panic_fn_id: Default::default(),
panic_bounds_check_fn_id: Default::default(),
i8_i16_atomics_allowed: false,
codegen_args,
}
}
@ -256,6 +261,51 @@ impl<'tcx> CodegenCx<'tcx> {
}
}
pub struct CodegenArgs {
pub module_output_type: ModuleOutputType,
}
impl CodegenArgs {
pub fn from_session(sess: &Session) -> Self {
match CodegenArgs::parse(&sess.opts.cg.llvm_args) {
Ok(ok) => ok,
Err(err) => sess.fatal(&format!("Unable to parse llvm-args: {}", err)),
}
}
pub fn parse(args: &[String]) -> Result<Self, rustc_session::getopts::Fail> {
use rustc_session::getopts;
let mut opts = getopts::Options::new();
opts.optopt(
"",
"module-output",
"single output or multiple output",
"[single|multiple]",
);
let matches = opts.parse(args)?;
let module_output_type =
matches.opt_get_default("module-output", ModuleOutputType::Single)?;
Ok(Self { module_output_type })
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ModuleOutputType {
Single,
Multiple,
}
impl FromStr for ModuleOutputType {
type Err = rustc_session::getopts::Fail;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"single" => Ok(Self::Single),
"multiple" => Ok(Self::Multiple),
v => Err(Self::Err::UnrecognizedOption(v.to_string())),
}
}
}
impl<'tcx> BackendTypes for CodegenCx<'tcx> {
type Value = SpirvValue;
type Function = SpirvValue;

View File

@ -118,7 +118,7 @@ mod spirv_type_constraints;
mod symbols;
use builder::Builder;
use codegen_cx::CodegenCx;
use codegen_cx::{CodegenArgs, CodegenCx, ModuleOutputType};
pub use rspirv;
use rspirv::binary::Assemble;
use rustc_ast::expand::allocator::AllocatorKind;
@ -380,6 +380,8 @@ impl CodegenBackend for SpirvCodegenBackend {
) -> Result<(), ErrorReported> {
// TODO: Can we merge this sym with the one in symbols.rs?
let legalize = !sess.target_features.contains(&Symbol::intern("kernel"));
let codegen_args = CodegenArgs::from_session(sess);
let emit_multiple_modules = codegen_args.module_output_type == ModuleOutputType::Multiple;
let timer = sess.timer("link_crate");
link::link(
@ -388,6 +390,7 @@ impl CodegenBackend for SpirvCodegenBackend {
outputs,
&codegen_results.crate_name.as_str(),
legalize,
emit_multiple_modules,
);
drop(timer);

View File

@ -13,11 +13,11 @@ use rustc_session::config::{CrateType, DebugInfo, Lto, OptLevel, OutputFilenames
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::env;
use std::ffi::{CString, OsStr};
use std::fs::File;
use std::io::{Read, Write};
use std::io::{BufWriter, Read, Write};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tar::{Archive, Builder, Header};
@ -28,6 +28,7 @@ pub fn link<'a>(
outputs: &OutputFilenames,
crate_name: &str,
legalize: bool,
emit_multiple_modules: bool,
) {
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
for &crate_type in sess.crate_types().iter() {
@ -60,9 +61,14 @@ pub fn link<'a>(
CrateType::Rlib => {
link_rlib(sess, codegen_results, &out_filename);
}
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => {
link_exe(sess, crate_type, &out_filename, codegen_results, legalize)
}
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => link_exe(
sess,
crate_type,
&out_filename,
codegen_results,
legalize,
emit_multiple_modules,
),
other => sess.err(&format!("CrateType {:?} not supported yet", other)),
}
}
@ -104,6 +110,7 @@ fn link_exe(
out_filename: &Path,
codegen_results: &CodegenResults,
legalize: bool,
emit_multiple_modules: bool,
) {
let mut objects = Vec::new();
let mut rlibs = Vec::new();
@ -122,8 +129,34 @@ fn link_exe(
codegen_results,
);
let spv_binary = do_link(sess, &objects, &rlibs, legalize);
let spv_binary = do_link(sess, &objects, &rlibs, legalize, emit_multiple_modules);
use rspirv::binary::Assemble;
match spv_binary {
linker::LinkResult::SingleModule(spv_binary) => {
post_link_single_module(sess, spv_binary.assemble(), out_filename);
}
linker::LinkResult::MultipleModules(map) => {
let mut root_file_name = out_filename.file_name().unwrap().to_owned();
root_file_name.push(".dir");
let out_dir = out_filename.with_file_name(root_file_name);
if !out_dir.is_dir() {
std::fs::create_dir_all(&out_dir).unwrap();
}
let mut hashmap = HashMap::new();
for (name, spv_binary) in map {
let mut module_filename = out_dir.clone();
module_filename.push(sanitize_filename::sanitize(&name));
post_link_single_module(sess, spv_binary.assemble(), &module_filename);
hashmap.insert(name, module_filename);
}
let file = File::create(out_filename).unwrap();
serde_json::to_writer(BufWriter::new(file), &hashmap).unwrap();
}
}
}
fn post_link_single_module(sess: &Session, spv_binary: Vec<u32>, out_filename: &Path) {
if let Ok(ref path) = std::env::var("DUMP_POST_LINK") {
File::create(path)
.unwrap()
@ -378,7 +411,13 @@ pub fn read_metadata(rlib: &Path) -> Result<MetadataRef, String> {
/// This is the actual guts of linking: the rest of the link-related functions are just digging through rustc's
/// shenanigans to collect all the object files we need to link.
fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: bool) -> Vec<u32> {
fn do_link(
sess: &Session,
objects: &[PathBuf],
rlibs: &[PathBuf],
legalize: bool,
emit_multiple_modules: bool,
) -> linker::LinkResult {
fn load(bytes: &[u8]) -> rspirv::dr::Module {
let mut loader = rspirv::dr::Loader::new();
rspirv::binary::parse_bytes(&bytes, &mut loader).unwrap();
@ -407,6 +446,7 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo
}
if let Ok(ref path) = env::var("DUMP_PRE_LINK") {
use rspirv::binary::Assemble;
let path = Path::new(path);
if path.is_file() {
std::fs::remove_file(path).unwrap();
@ -429,21 +469,18 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo
mem2reg: legalize,
structurize: env::var("NO_STRUCTURIZE").is_err(),
use_new_structurizer: env::var("OLD_STRUCTURIZER").is_err(),
emit_multiple_modules,
};
let link_result = linker::link(sess, modules, &options);
let assembled = match link_result {
match link_result {
Ok(v) => v,
Err(rustc_errors::ErrorReported) => {
sess.abort_if_errors();
bug!("Linker errored, but no error reported")
}
};
// And finally write out the linked binary.
use rspirv::binary::Assemble;
assembled.assemble()
}
}
/// As of right now, this is essentially a no-op, just plumbing through all the files.

View File

@ -73,6 +73,9 @@ fn kill_unrooted(module: &mut Module, rooted: &HashSet<Word>) {
module
.ext_inst_imports
.retain(|inst| is_rooted(inst, rooted));
module
.execution_modes
.retain(|inst| is_rooted(inst, rooted));
module.debugs.retain(|inst| is_rooted(inst, rooted));
module.annotations.retain(|inst| is_rooted(inst, rooted));
module

View File

@ -30,6 +30,12 @@ pub struct Options {
pub mem2reg: bool,
pub structurize: bool,
pub use_new_structurizer: bool,
pub emit_multiple_modules: bool,
}
pub enum LinkResult {
SingleModule(Module),
MultipleModules(HashMap<String, Module>),
}
fn id(header: &mut ModuleHeader) -> Word {
@ -70,9 +76,7 @@ fn apply_rewrite_rules(rewrite_rules: &HashMap<Word, Word>, blocks: &mut [Block]
}
}
// Sess needs to be Option because linker tests call this method, and linker tests can't synthesize
// a test Session (not sure how to do that).
pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<Module> {
pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<LinkResult> {
let mut output = {
let _timer = sess.timer("link_merge");
// shift all the ids
@ -241,18 +245,54 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<M
simple_passes::sort_globals(&mut output);
}
let mut output = if opts.emit_multiple_modules {
let modules = output
.entry_points
.iter()
.map(|entry| {
let mut module = output.clone();
module.entry_points.clear();
module.entry_points.push(entry.clone());
let name = entry.operands[2].unwrap_literal_string();
(name.to_string(), module)
})
.collect();
LinkResult::MultipleModules(modules)
} else {
LinkResult::SingleModule(output)
};
let output_module_iter: Box<dyn Iterator<Item = &mut Module>> = match output {
LinkResult::SingleModule(ref mut m) => Box::new(std::iter::once(m)),
LinkResult::MultipleModules(ref mut m) => Box::new(m.values_mut()),
};
for output in output_module_iter {
if let Ok(ref path) = std::env::var("DUMP_POST_SPLIT") {
use rspirv::binary::Assemble;
use std::fs::File;
use std::io::Write;
File::create(path)
.unwrap()
.write_all(spirv_tools::binary::from_binary(&output.assemble()))
.unwrap();
}
if opts.dce && opts.emit_multiple_modules {
let _timer = sess.timer("link_dce_2");
dce::dce(output);
}
{
let _timer = sess.timer("link_remove_extra_capabilities");
capability_computation::remove_extra_capabilities(&mut output);
capability_computation::remove_extra_extensions(&mut output);
capability_computation::remove_extra_capabilities(output);
capability_computation::remove_extra_extensions(output);
}
if opts.compact_ids {
let _timer = sess.timer("link_compact_ids");
// compact the ids https://github.com/KhronosGroup/SPIRV-Tools/blob/e02f178a716b0c3c803ce31b9df4088596537872/source/opt/compact_ids_pass.cpp#L43
output.header.as_mut().unwrap().bound = simple_passes::compact_ids(&mut output);
output.header.as_mut().unwrap().bound = simple_passes::compact_ids(output);
};
}
// output the module
Ok(output)
}

View File

@ -1,4 +1,4 @@
use super::{link, Options};
use super::{link, LinkResult, Options};
use pipe::pipe;
use rspirv::dr::{Loader, Module};
use rustc_driver::handle_options;
@ -95,10 +95,14 @@ fn assemble_and_link(binaries: &[&[u8]]) -> Result<Module, String> {
mem2reg: false,
structurize: false,
use_new_structurizer: false,
emit_multiple_modules: false,
},
);
assert_eq!(compiler.session().has_errors(), res.is_err());
res
res.map(|res| match res {
LinkResult::SingleModule(m) => m,
LinkResult::MultipleModules(_) => unreachable!(),
})
})
.map_err(|_e| thread.join().unwrap())
}

View File

@ -64,18 +64,32 @@ use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
#[derive(Debug)]
pub enum SpirvBuilderError {
BuildFailed,
MultiModuleWithPrintMetadata,
MetadataFileMissing(std::io::Error),
MetadataFileMalformed(serde_json::Error),
}
impl fmt::Display for SpirvBuilderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SpirvBuilderError::BuildFailed => f.write_str("Build failed"),
SpirvBuilderError::MultiModuleWithPrintMetadata => {
f.write_str("Multi-module build cannot be used with print_metadata = true")
}
SpirvBuilderError::MetadataFileMissing(_) => {
f.write_str("Multi-module metadata file missing")
}
SpirvBuilderError::MetadataFileMalformed(_) => {
f.write_str("Unable to parse multi-module metadata file")
}
}
}
}
@ -134,13 +148,25 @@ impl SpirvBuilder {
/// you usually don't have to inspect the path, as the environment variable will already be
/// set.
pub fn build(self) -> Result<PathBuf, SpirvBuilderError> {
let spirv_module = invoke_rustc(&self)?;
let spirv_module = invoke_rustc(&self, false)?;
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
if self.print_metadata {
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
}
Ok(spirv_module)
}
pub fn build_multimodule(self) -> Result<HashMap<String, PathBuf>, SpirvBuilderError> {
if self.print_metadata {
return Err(SpirvBuilderError::MultiModuleWithPrintMetadata);
}
let metadata_file = invoke_rustc(&self, true)?;
let metadata_contents =
File::open(metadata_file).map_err(SpirvBuilderError::MetadataFileMissing)?;
let metadata = serde_json::from_reader(BufReader::new(metadata_contents))
.map_err(SpirvBuilderError::MetadataFileMalformed)?;
Ok(metadata)
}
}
// https://github.com/rust-lang/cargo/blob/1857880b5124580c4aeb4e8bc5f1198f491d61b1/src/cargo/util/paths.rs#L29-L52
@ -175,7 +201,8 @@ fn find_rustc_codegen_spirv() -> PathBuf {
panic!("Could not find {} in library path", filename);
}
fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
// Note: in case of multimodule, returns path to the metadata json
fn invoke_rustc(builder: &SpirvBuilder, multimodule: bool) -> Result<PathBuf, SpirvBuilderError> {
// Okay, this is a little bonkers: in a normal world, we'd have the user clone
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
// the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@ -205,10 +232,16 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
} else {
format!(" -C target-feature={}", target_features.join(","))
};
let llvm_args = if multimodule {
" -C llvm-args=--module-output=multiple"
} else {
""
};
let rustflags = format!(
"-Z codegen-backend={} -Z symbol-mangling-version=v0{}",
"-Z codegen-backend={} -Z symbol-mangling-version=v0{}{}",
rustc_codegen_spirv.display(),
feature_flag,
llvm_args,
);
let mut cargo = Command::new("cargo");
cargo.args(&[

View File

@ -0,0 +1,16 @@
[package]
name = "multibuilder"
version = "0.1.0"
authors = ["Embark <opensource@embark-studios.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
publish = false
# See rustc_codegen_spirv/Cargo.toml for details on these features
[features]
default = ["use-compiled-tools"]
use-installed-tools = ["spirv-builder/use-installed-tools"]
use-compiled-tools = ["spirv-builder/use-compiled-tools"]
[dependencies]
spirv-builder = { path = "../../crates/spirv-builder", default-features = false }

View File

@ -0,0 +1,10 @@
use spirv_builder::SpirvBuilder;
fn main() {
let result = SpirvBuilder::new("../shaders/sky-shader")
.print_metadata(false)
.spirv_version(1, 0)
.build_multimodule()
.unwrap();
println!("{:#?}", result);
}

View File

@ -18,7 +18,10 @@ pub fn main_fs(output: &mut Vec4) {
}
#[spirv(vertex)]
pub fn main_vs(#[spirv(vertex_index)] vert_id: i32, #[spirv(position)] out_pos: &mut Vec4) {
pub fn main_vs(
#[spirv(vertex_index)] vert_id: i32,
#[spirv(position, invariant)] out_pos: &mut Vec4,
) {
*out_pos = vec4(
(vert_id - 1) as f32,
((vert_id & 1) * 2 - 1) as f32,