First try at spirv-builder

This commit is contained in:
khyperia 2020-10-09 17:22:07 +02:00
parent 6323fc609f
commit 1516d864f3
24 changed files with 2275 additions and 222 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
/target
target/

1037
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
[workspace]
members = [
"examples/example-runner",
"rspirv-linker",
"rustc_codegen_spirv",
"spirv-builder",
"spirv-std",
]

View File

@ -0,0 +1,14 @@
[package]
name = "example-runner"
version = "0.1.0"
authors = ["Embark <opensource@embark-studios.com>"]
edition = "2018"
[dependencies]
winit = "0.19.5"
image = "0.10.4"
ash = "0.31"
ash-window = "0.5"
[build-dependencies]
spirv-builder = { path = "../../spirv-builder" }

View File

@ -0,0 +1,8 @@
use spirv_builder::build_spirv;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// This will set the env var `example-shader.spv` to a spir-v file that can be include!()'d
build_spirv("../../rustc_codegen_spirv", "../example-shader")?;
Ok(())
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

12
examples/example-shader/Cargo.lock generated Normal file
View File

@ -0,0 +1,12 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "example-shader"
version = "0.1.0"
dependencies = [
"spirv-std",
]
[[package]]
name = "spirv-std"
version = "0.1.0"

View File

@ -0,0 +1,15 @@
[package]
name = "example-shader"
version = "0.1.0"
authors = ["Embark <opensource@embark-studios.com>"]
edition = "2018"
[lib]
crate-type = ["dylib"]
[dependencies]
spirv-std = { path = "../../spirv-std" }
# This crate is built specially by the example-runner crate, and so therefore
# should be excluded from the top-level `cargo build` etc.
[workspace]

View File

@ -0,0 +1,17 @@
#![no_std]
#![feature(register_attr)]
#![register_attr(spirv)]
use core::panic::PanicInfo;
use spirv_std::{f32x4, Input, Output};
#[allow(unused_attributes)]
#[spirv(entry = "fragment")]
pub fn main(input: Input<f32x4>, mut output: Output<f32x4>) {
output.store(input.load())
}
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}
}

View File

@ -1,9 +0,0 @@
setlocal
cargo build
set RUSTFLAGS=-Zcodegen-backend=%cd%/../target/debug/rustc_codegen_spirv.dll
pushd build_libcore_test
set SPIRV_VAL=1
cargo build -Z build-std=core --target spirv-unknown-unknown --release
popd

View File

@ -1,13 +0,0 @@
#!/usr/bin/env bash
# exit on cmd failure
set -e
# build rustc_codegen_spirv
cargo build
export RUSTFLAGS="-Zcodegen-backend=$PWD/../target/debug/librustc_codegen_spirv.so"
pushd build_libcore_test
SPIRV_VAL=${SPIRV_VAL-1} cargo build -Z build-std=core --target spirv-unknown-unknown --release
popd

View File

@ -1,2 +0,0 @@
/target/
/Cargo.lock

View File

@ -1,13 +0,0 @@
[package]
name = "build_libcore_test"
version = "0.1.0"
authors = ["Ashley Hauck <ashley.hauck@embark-studios.com>"]
edition = "2018"
[lib]
crate-type = ["dylib"]
[dependencies]
spirv-std = { path = "../../spirv-std" }
[workspace]

View File

@ -1,28 +0,0 @@
#![no_std]
#![feature(register_attr)]
#![register_attr(spirv)]
use core::panic::PanicInfo;
#[cfg(not(target_feature = "shader"))]
use spirv_std::CrossWorkgroup;
#[cfg(target_feature = "shader")]
use spirv_std::{f32x4, Input, Output};
#[cfg(target_feature = "shader")]
#[allow(unused_attributes)]
#[spirv(entry = "fragment")]
pub fn main(input: Input<f32x4>, mut output: Output<f32x4>) {
output.store(input.load())
}
#[cfg(not(target_feature = "shader"))]
#[allow(unused_attributes)]
#[spirv(entry = "kernel")]
pub fn add_two_ints(x: CrossWorkgroup<u32>, y: CrossWorkgroup<u32>, mut z: CrossWorkgroup<u32>) {
z.store(x.load() + y.load())
}
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}
}

View File

@ -1,2 +0,0 @@
/target/
/Cargo.lock

View File

@ -1,10 +0,0 @@
[package]
name = "run_libcore_test"
version = "0.1.0"
authors = ["Ashley Hauck <ashley.hauck@embark-studios.com>"]
edition = "2018"
[dependencies]
ocl = { version = "", features = ["opencl_version_2_1"] }
[workspace]

View File

@ -1,80 +0,0 @@
use ocl::enums::ProgramInfo;
use ocl::{Buffer, Context, Kernel, Platform, Program, Queue};
use std::ffi::CString;
use std::fs::File;
use std::io::Read;
fn main() {
let path = "../build_libcore_test/target/spirv-unknown-unknown/release/build_libcore_test.spv";
let mut spirv = Vec::new();
File::open(path).unwrap().read_to_end(&mut spirv).unwrap();
let platform = Platform::list()
.into_iter()
.find(|p| p.version().unwrap().contains("2."))
.unwrap();
let context = Context::builder().platform(platform).build().unwrap();
let device = context.devices()[0];
println!(
"Using {} -> {}",
platform.name().unwrap(),
device.name().unwrap()
);
let queue = Queue::new(&context, device, None).unwrap();
let program = Program::with_il(
&spirv,
Some(&[device]),
&CString::new("").unwrap(),
&context,
)
.unwrap();
println!(
"Kernel names: {:?}",
program.info(ProgramInfo::KernelNames).unwrap()
);
let one = Buffer::<u32>::builder()
.queue(queue.clone())
.len(1)
.build()
.unwrap();
let two = Buffer::<u32>::builder()
.queue(queue.clone())
.len(1)
.build()
.unwrap();
let three = Buffer::<u32>::builder()
.queue(queue.clone())
.len(1)
.build()
.unwrap();
one.write(&[1u32] as &[u32]).enq().unwrap();
two.write(&[2u32] as &[u32]).enq().unwrap();
three.write(&[5u32] as &[u32]).enq().unwrap();
let kernel = Kernel::builder()
.queue(queue.clone())
.program(&program)
.name("add_two_ints.1")
.local_work_size(&[1])
.global_work_size(&[1])
.arg(&one)
.arg(&two)
.arg(&three)
.build()
.unwrap();
unsafe {
kernel.enq().unwrap();
}
fn read(buf: Buffer<u32>) {
let mut vec = vec![0; 1];
buf.read(&mut vec).enq().unwrap();
println!("{:?}", vec);
}
read(one);
read(two);
read(three);
}

View File

@ -273,7 +273,6 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> {
let cast_dst = self.pointercast(dst.llval, cast_ptr_ty);
self.store(val, cast_dst, arg_abi.layout.align.abi);
} else {
// TODO: Does this need a from_immediate? The LLVM backend doesn't have one here.
OperandValue::Immediate(val).store(self, dst);
}
}
@ -284,9 +283,7 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> {
}
impl<'a, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'tcx> {
fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
// TODO: Implement this?
}
fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {}
fn get_param(&self, index: usize) -> Self::Value {
self.function_parameter_values.borrow()[&self.current_fn.def][index]

View File

@ -1,36 +0,0 @@
use std::path::Path;
use std::process::Command;
#[test]
pub fn build_libcore_test() {
{
// Unfortunately, as of right now, cargo does not rebuild projects if the .so provided by
// codegen-backend has changed. So, force a full rebuild always by deleting the target dir.
let target_dir = Path::new("build_libcore_test/target");
if target_dir.exists() {
std::fs::remove_dir_all(target_dir).unwrap();
}
}
let rustflags = format!(
"-Z codegen-backend={}rustc_codegen_spirv{}",
std::env::consts::DLL_PREFIX,
std::env::consts::DLL_SUFFIX
);
let build = Command::new("cargo")
.args(&[
"build",
"-Z",
"build-std=core",
"--target",
"spirv-unknown-unknown",
"--release",
])
.current_dir(Path::new("build_libcore_test").canonicalize().unwrap())
.env("RUSTFLAGS", rustflags)
.env("SPIRV_VAL", "1")
.status()
.expect("failed to execute cargo build");
if !build.success() {
panic!("build_libcore_test compilation failed with code {}", build);
}
}

11
spirv-builder/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "spirv-builder"
version = "0.1.0"
authors = ["khyperia <github@khyperia.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "", features = ["derive"] }
serde_json = ""

103
spirv-builder/src/lib.rs Normal file
View File

@ -0,0 +1,103 @@
use serde::Deserialize;
use std::error::Error;
use std::fmt;
use std::path::Path;
use std::process::{Command, Output};
#[derive(Debug)]
pub enum SpirvBuilderError {
BuildFailed(Output),
}
impl fmt::Display for SpirvBuilderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SpirvBuilderError::BuildFailed(output) => write!(
f,
"{}\nstdout:\n{}\nstderr:\n{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
),
}
}
}
impl Error for SpirvBuilderError {}
pub fn build_spirv(
path_to_rustc_codegen_spirv: impl AsRef<Path>,
path_to_crate: impl AsRef<Path>,
) -> Result<(), SpirvBuilderError> {
let path_to_built_codegen = build_rustc_codegen_spirv(path_to_rustc_codegen_spirv.as_ref())?;
let spirv_module = invoke_rustc(path_to_built_codegen, path_to_crate.as_ref())?;
let spirv_path: &Path = spirv_module.as_ref();
let env_var = spirv_path.file_name().unwrap().to_str().unwrap();
println!("cargo:rustc-env={}={}", env_var, spirv_module);
Ok(())
}
#[derive(Deserialize)]
struct RustcOutput {
reason: String,
filenames: Option<Vec<String>>,
}
fn get_last_artifact(out: &str) -> String {
let out = serde_json::Deserializer::from_str(out).into_iter::<RustcOutput>();
let last = out
.map(|line| line.unwrap())
.filter(|line| line.reason == "compiler-artifact")
.last()
.expect("Did not find output file in rustc output");
let mut filenames = last.filenames.unwrap();
println!("{:?}", filenames);
assert_eq!(filenames.len(), 1);
filenames.pop().unwrap()
}
fn build_rustc_codegen_spirv(path_to_codegen: &Path) -> Result<String, SpirvBuilderError> {
let build = Command::new("cargo")
.args(&[
"build",
"--message-format=json-render-diagnostics",
"--release",
])
.current_dir(path_to_codegen.canonicalize().unwrap())
.output()
.expect("failed to execute cargo build");
if build.status.success() {
Ok(get_last_artifact(&String::from_utf8(build.stdout).unwrap()))
} else {
Err(SpirvBuilderError::BuildFailed(build))
}
}
fn invoke_rustc(
path_to_built_codegen: String,
path_to_crate: &Path,
) -> Result<String, SpirvBuilderError> {
let rustflags = format!(
"-Z codegen-backend={} -C target-feature=+shader",
path_to_built_codegen
);
let build = Command::new("cargo")
.args(&[
"build",
"--message-format=json-render-diagnostics",
"-Z",
"build-std=core",
"--target",
"spirv-unknown-unknown",
"--release",
])
.current_dir(path_to_crate.canonicalize().unwrap())
.env("RUSTFLAGS", rustflags)
.env("SPIRV_VAL", "1")
.output()
.expect("failed to execute cargo build");
if build.status.success() {
Ok(get_last_artifact(&String::from_utf8(build.stdout).unwrap()))
} else {
Err(SpirvBuilderError::BuildFailed(build))
}
}