mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-22 06:45:13 +00:00
Add support for spir-v 1.0 (#165)
This commit is contained in:
parent
706f4cc695
commit
23819c7a2c
@ -3,6 +3,8 @@ use std::error::Error;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// This will set the env var `wgpu-example-shader.spv` to a spir-v file that can be include!()'d
|
||||
SpirvBuilder::new("../wgpu-example-shader").build()?;
|
||||
SpirvBuilder::new("../wgpu-example-shader")
|
||||
.spirv_version(1, 0)
|
||||
.build()?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -71,10 +71,11 @@ pub struct BuilderSpirv {
|
||||
}
|
||||
|
||||
impl BuilderSpirv {
|
||||
pub fn new(kernel_mode: bool) -> Self {
|
||||
pub fn new(version: Option<(u8, u8)>, kernel_mode: bool) -> Self {
|
||||
let mut builder = Builder::new();
|
||||
// intel-compute-runtime only supports v1.3
|
||||
builder.set_version(1, 3);
|
||||
// Default to spir-v 1.3
|
||||
let version = version.unwrap_or((1, 3));
|
||||
builder.set_version(version.0, version.1);
|
||||
if kernel_mode {
|
||||
builder.capability(Capability::Kernel);
|
||||
} else {
|
||||
@ -82,6 +83,9 @@ impl BuilderSpirv {
|
||||
builder.capability(Capability::Shader);
|
||||
builder.capability(Capability::VulkanMemoryModel);
|
||||
builder.capability(Capability::VariablePointers);
|
||||
if version < (1, 3) {
|
||||
builder.extension("SPV_KHR_variable_pointers");
|
||||
}
|
||||
}
|
||||
// The linker will always be ran on this module
|
||||
builder.capability(Capability::Linkage);
|
||||
|
@ -63,11 +63,29 @@ pub struct CodegenCx<'tcx> {
|
||||
impl<'tcx> CodegenCx<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>) -> Self {
|
||||
let sym = Box::new(Symbols::new());
|
||||
let kernel_mode = tcx.sess.target_features.contains(&sym.kernel);
|
||||
let mut kernel_mode = false;
|
||||
let mut spirv_version = None;
|
||||
for &feature in &tcx.sess.target_features {
|
||||
if feature == sym.kernel {
|
||||
kernel_mode = true;
|
||||
} else if feature == sym.spirv10 {
|
||||
spirv_version = Some((1, 0));
|
||||
} else if feature == sym.spirv11 {
|
||||
spirv_version = Some((1, 1));
|
||||
} else if feature == sym.spirv12 {
|
||||
spirv_version = Some((1, 2));
|
||||
} else if feature == sym.spirv13 {
|
||||
spirv_version = Some((1, 3));
|
||||
} else if feature == sym.spirv14 {
|
||||
spirv_version = Some((1, 4));
|
||||
} else if feature == sym.spirv15 {
|
||||
spirv_version = Some((1, 5));
|
||||
}
|
||||
}
|
||||
Self {
|
||||
tcx,
|
||||
codegen_unit,
|
||||
builder: BuilderSpirv::new(kernel_mode),
|
||||
builder: BuilderSpirv::new(spirv_version, kernel_mode),
|
||||
instances: Default::default(),
|
||||
function_parameter_values: Default::default(),
|
||||
type_cache: Default::default(),
|
||||
|
@ -223,15 +223,6 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options)
|
||||
output.header.as_mut().unwrap().bound = simple_passes::compact_ids(&mut output);
|
||||
};
|
||||
|
||||
output.debugs.push(Instruction::new(
|
||||
Op::ModuleProcessed,
|
||||
None,
|
||||
None,
|
||||
vec![Operand::LiteralString(
|
||||
"Linked by rspirv-linker".to_string(),
|
||||
)],
|
||||
));
|
||||
|
||||
// output the module
|
||||
Ok(output)
|
||||
}
|
||||
|
@ -138,8 +138,7 @@ fn standard() -> Result<()> {
|
||||
);
|
||||
|
||||
let result = assemble_and_link(&[&a, &b])?;
|
||||
let expect = r#"OpModuleProcessed "Linked by rspirv-linker"
|
||||
%1 = OpTypeFloat 32
|
||||
let expect = r#"%1 = OpTypeFloat 32
|
||||
%2 = OpVariable %1 Input
|
||||
%3 = OpConstant %1 42.0
|
||||
%4 = OpVariable %1 Uniform %3"#;
|
||||
@ -158,8 +157,7 @@ fn not_a_lib_extra_exports() -> Result<()> {
|
||||
);
|
||||
|
||||
let result = assemble_and_link(&[&a])?;
|
||||
let expect = r#"OpModuleProcessed "Linked by rspirv-linker"
|
||||
%1 = OpTypeFloat 32
|
||||
let expect = r#"%1 = OpTypeFloat 32
|
||||
%2 = OpVariable %1 Uniform"#;
|
||||
without_header_eq(result, expect);
|
||||
Ok(())
|
||||
@ -178,8 +176,7 @@ fn lib_extra_exports() -> Result<()> {
|
||||
|
||||
let result = assemble_and_link(&[&a])?;
|
||||
|
||||
let expect = r#"OpModuleProcessed "Linked by rspirv-linker"
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
let expect = r#"OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform"#;
|
||||
without_header_eq(result, expect);
|
||||
@ -363,8 +360,7 @@ fn func_ctrl() -> Result<()> {
|
||||
|
||||
let result = assemble_and_link(&[&a, &b])?;
|
||||
|
||||
let expect = r#"OpModuleProcessed "Linked by rspirv-linker"
|
||||
%1 = OpTypeVoid
|
||||
let expect = r#"%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpTypeFloat 32
|
||||
%4 = OpVariable %3 Uniform
|
||||
@ -417,7 +413,6 @@ fn use_exported_func_param_attr() -> Result<()> {
|
||||
let result = assemble_and_link(&[&a, &b])?;
|
||||
|
||||
let expect = r#"OpCapability Kernel
|
||||
OpModuleProcessed "Linked by rspirv-linker"
|
||||
OpDecorate %1 FuncParamAttr Zext
|
||||
%1 = OpDecorationGroup
|
||||
OpGroupDecorate %1 %2
|
||||
@ -487,7 +482,6 @@ fn names_and_decorations() -> Result<()> {
|
||||
let expect = r#"OpCapability Kernel
|
||||
OpName %1 "foo"
|
||||
OpName %2 "param"
|
||||
OpModuleProcessed "Linked by rspirv-linker"
|
||||
OpDecorate %3 Restrict
|
||||
OpDecorate %4 NonWritable
|
||||
%3 = OpDecorationGroup
|
||||
|
@ -13,6 +13,12 @@ pub struct Symbols {
|
||||
pub spirv: Symbol,
|
||||
pub spirv_std: Symbol,
|
||||
pub kernel: Symbol,
|
||||
pub spirv10: Symbol,
|
||||
pub spirv11: Symbol,
|
||||
pub spirv12: Symbol,
|
||||
pub spirv13: Symbol,
|
||||
pub spirv14: Symbol,
|
||||
pub spirv15: Symbol,
|
||||
descriptor_set: Symbol,
|
||||
binding: Symbol,
|
||||
attributes: HashMap<Symbol, SpirvAttribute>,
|
||||
@ -211,6 +217,12 @@ impl Symbols {
|
||||
spirv: Symbol::intern("spirv"),
|
||||
spirv_std: Symbol::intern("spirv_std"),
|
||||
kernel: Symbol::intern("kernel"),
|
||||
spirv10: Symbol::intern("spirv1.0"),
|
||||
spirv11: Symbol::intern("spirv1.1"),
|
||||
spirv12: Symbol::intern("spirv1.2"),
|
||||
spirv13: Symbol::intern("spirv1.3"),
|
||||
spirv14: Symbol::intern("spirv1.4"),
|
||||
spirv15: Symbol::intern("spirv1.5"),
|
||||
descriptor_set: Symbol::intern("descriptor_set"),
|
||||
binding: Symbol::intern("binding"),
|
||||
attributes,
|
||||
|
@ -30,12 +30,14 @@ impl Error for SpirvBuilderError {}
|
||||
pub struct SpirvBuilder {
|
||||
path_to_crate: PathBuf,
|
||||
print_metadata: bool,
|
||||
spirv_version: Option<(u8, u8)>,
|
||||
}
|
||||
impl SpirvBuilder {
|
||||
pub fn new(path_to_crate: impl AsRef<Path>) -> Self {
|
||||
Self {
|
||||
path_to_crate: path_to_crate.as_ref().to_owned(),
|
||||
print_metadata: true,
|
||||
spirv_version: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,11 +47,20 @@ impl SpirvBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn spirv_version(mut self, major: u8, minor: u8) -> Self {
|
||||
self.spirv_version = Some((major, minor));
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the module. Returns the path to the built spir-v file. If print_metadata is true,
|
||||
/// 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.path_to_crate.as_ref(), self.print_metadata)?;
|
||||
let spirv_module = invoke_rustc(
|
||||
self.path_to_crate.as_ref(),
|
||||
self.print_metadata,
|
||||
self.spirv_version,
|
||||
)?;
|
||||
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
|
||||
if self.print_metadata {
|
||||
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
|
||||
@ -90,7 +101,11 @@ fn find_rustc_codegen_spirv() -> PathBuf {
|
||||
panic!("Could not find {} in library path", filename);
|
||||
}
|
||||
|
||||
fn invoke_rustc(path_to_crate: &Path, print_metadata: bool) -> Result<PathBuf, SpirvBuilderError> {
|
||||
fn invoke_rustc(
|
||||
path_to_crate: &Path,
|
||||
print_metadata: bool,
|
||||
spirv_version: Option<(u8, u8)>,
|
||||
) -> 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
|
||||
@ -100,7 +115,15 @@ fn invoke_rustc(path_to_crate: &Path, print_metadata: bool) -> Result<PathBuf, S
|
||||
// rustc expects a full path, instead of a filename looked up via LD_LIBRARY_PATH, so we need
|
||||
// to copy cargo's understanding of library lookup and find the library and its full path.
|
||||
let rustc_codegen_spirv = find_rustc_codegen_spirv();
|
||||
let rustflags = format!("-Z codegen-backend={}", rustc_codegen_spirv.display());
|
||||
let spirv_version_feture = match spirv_version {
|
||||
None => "".to_string(),
|
||||
Some((major, minor)) => format!(" -C target-feature=+spirv{}.{}", major, minor),
|
||||
};
|
||||
let rustflags = format!(
|
||||
"-Z codegen-backend={}{}",
|
||||
rustc_codegen_spirv.display(),
|
||||
spirv_version_feture
|
||||
);
|
||||
let build = Command::new("cargo")
|
||||
.args(&[
|
||||
"build",
|
||||
|
Loading…
Reference in New Issue
Block a user