Initial xtask check-in

This commit is contained in:
Bradlee Speice 2025-01-01 17:32:11 -05:00
commit 52110f4e29
17 changed files with 439 additions and 0 deletions

4
.cargo/config.toml Normal file
View File

@ -0,0 +1,4 @@
[alias]
shader-compile = "run --package xtask -- shader-compile"
shader-test = "run --package xtask -- shader-test"
xtask = "run --package xtask --"

View File

@ -0,0 +1,13 @@
{
"name": "Rust",
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bookworm",
"runArgs": ["--userns=keep-id"],
"containerUser": "vscode",
"customizations": {
"vscode": {
"extensions": [
"shader-slang.slang-language-extension"
]
}
}
}

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target
.idea/
cmake-build-*

48
Cargo.lock generated Normal file
View File

@ -0,0 +1,48 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "xflags"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d9e15fbb3de55454b0106e314b28e671279009b363e6f1d8e39fdc3bf048944"
dependencies = [
"xflags-macros",
]
[[package]]
name = "xflags-macros"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155"
[[package]]
name = "xshell"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d"
dependencies = [
"xshell-macros",
]
[[package]]
name = "xshell-macros"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
[[package]]
name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
"xflags",
"xshell",
]

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[workspace]
members = [
"crates/xtask"
]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
[workspace.dependencies]
anyhow = "1.0"

10
crates/flare/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "flare"
version.workspace = true
edition.workspace = true
[dependencies]
[build-dependencies]
reqwest.workspace = true
zip-extract.workspace = true

29
crates/flare/build.rs Normal file
View File

@ -0,0 +1,29 @@
use std::env;
use std::fs::{File};
use std::io::{BufReader, Write};
use std::path::PathBuf;
use std::process::Command;
pub fn main() {
/*
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=../shader");
let url = "https://github.com/shader-slang/slang/releases/download/v2024.17/slang-2024.17-linux-x86_64.zip";
let output_path = PathBuf::from(format!("{}/slang.zip", env::var("OUT_DIR").unwrap()));
let output_dir = PathBuf::from(format!("{}/slang", env::var("OUT_DIR").unwrap()));
let mut response = reqwest::blocking::get(url).expect("Unable to fetch shader compiler");
let mut response_out = File::create(&output_path).unwrap();
response.copy_to(&mut response_out).expect("Unable to copy file");
response_out.flush().expect("Unable to flush output file");
let response_out = File::open(output_path).expect("Unable to create output file");
let output_reader = BufReader::new(response_out);
zip_extract::extract(output_reader, output_dir.as_path(), true).expect("Unable to extract shader compiler");
let slangc_path = output_dir.join("bin/slangc");
let shader_path= PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("../../shader");
*/
}

14
crates/flare/src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

10
crates/xtask/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "xtask"
edition.workspace = true
version.workspace = true
publish = false
[dependencies]
anyhow.workspace = true
xflags = "0.3"
xshell = "0.2"

56
crates/xtask/src/flags.rs Normal file
View File

@ -0,0 +1,56 @@
use std::path::PathBuf;
xflags::xflags! {
src "./src/flags.rs"
cmd xtask {
cmd shader-compile {
optional -S, --source source: PathBuf
}
cmd shader-test {
optional -S, --source source: PathBuf
}
}
}
// generated start
// The following code is generated by `xflags` macro.
// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
#[derive(Debug)]
pub struct Xtask {
pub subcommand: XtaskCmd,
}
#[derive(Debug)]
pub enum XtaskCmd {
ShaderCompile(ShaderCompile),
ShaderTest(ShaderTest),
}
#[derive(Debug)]
pub struct ShaderCompile {
pub source: Option<PathBuf>,
}
#[derive(Debug)]
pub struct ShaderTest {
pub source: Option<PathBuf>,
}
impl Xtask {
#[allow(dead_code)]
pub fn from_env_or_exit() -> Self {
Self::from_env_or_exit_()
}
#[allow(dead_code)]
pub fn from_env() -> xflags::Result<Self> {
Self::from_env_()
}
#[allow(dead_code)]
pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
Self::from_vec_(args)
}
}
// generated end

21
crates/xtask/src/main.rs Normal file
View File

@ -0,0 +1,21 @@
mod flags;
mod shader_compile;
mod shader_test;
mod slang_build;
use std::path::PathBuf;
use xshell::{Shell};
use crate::flags::XtaskCmd;
fn main() -> anyhow::Result<()> {
let project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
let sh = Shell::new()?;
sh.change_dir(project_root);
let flags = flags::Xtask::from_env_or_exit();
match flags.subcommand {
XtaskCmd::ShaderCompile(cmd) => cmd.run(&sh),
XtaskCmd::ShaderTest(cmd) => cmd.run(&sh),
}
}

View File

@ -0,0 +1,19 @@
use crate::flags;
use crate::slang_build::SlangBuild;
use xshell::Shell;
impl flags::ShaderCompile {
pub(crate) fn run(&self, sh: &Shell) -> anyhow::Result<()> {
let targets = ["slangc", "slang-glslang"];
let build_path = SlangBuild::new(self.source.as_ref()).build_targets(&sh, &targets)?;
let slangc_path = format!("{}/Release/bin/slangc", build_path.display());
sh.create_dir("target/xtask/shader")?;
sh.cmd(&slangc_path)
.args(["-target", "spirv"])
.args(["-o", "target/xtask/shader/hello-world.spv"])
.arg("shader/hello-world.slang")
.run()?;
Ok(())
}
}

View File

@ -0,0 +1,34 @@
use crate::flags::ShaderTest;
use crate::slang_build::SlangBuild;
use xshell::Shell;
impl ShaderTest {
pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
// Pending resolution of https://github.com/shader-slang/slang/issues/5979
/*
sh.cmd(format!("{}/Release/bin/slang-test", build_dir.display()))
.args(["-category", "compute"])
.args(["-test-dir", "shader-tests"])
.run()?;
Ok(())
*/
let targets = ["slang-test"];
let build_dir = SlangBuild::new(self.source.as_ref()).build_targets(&sh, &targets)?;
let build_dir = build_dir.to_str().unwrap();
// slang-test currently relies on a folder named `tests/` in the current directory
sh.cmd("cp")
.arg("-r")
.arg("shader-tests")
.arg(format!("{build_dir}/tests"))
.run()?;
let _dir_guard = sh.push_dir(&build_dir);
sh.cmd(format!("Release/bin/slang-test"))
.args(["-category", "compute"])
.run()?;
Ok(())
}
}

View File

@ -0,0 +1,83 @@
use anyhow::Context;
use std::path::{Path, PathBuf};
use std::thread::available_parallelism;
use xshell::Shell;
#[derive(Debug, Default, Clone)]
pub(crate) struct SlangBuild {
source: Option<PathBuf>,
}
impl SlangBuild {
pub(crate) fn new<P: AsRef<Path>>(source: Option<P>) -> Self {
Self {
source: source.map(|path| path.as_ref().to_path_buf()),
}
}
}
impl SlangBuild {
pub(crate) fn assure_source(self: &Self, sh: &Shell) -> anyhow::Result<PathBuf> {
if self.source.as_ref().is_some_and(|source| source.exists()) {
return Ok(self.source.as_ref().unwrap().clone());
}
let clone_dir = PathBuf::from("target/xtask/slang");
if clone_dir.exists() {
return Ok(clone_dir);
}
let _ = sh
.cmd("git")
.arg("clone")
.args(["--branch", "v2024.17"])
.args(["--depth", "1"])
.arg("--recurse-submodules")
.arg("--shallow-submodules")
.arg(format!("-j{}", available_parallelism()?))
.arg("https://github.com/shader-slang/slang")
.arg(clone_dir.to_str().unwrap())
.run()?;
Ok(clone_dir)
}
pub(crate) fn assure_build(self: &Self, sh: &Shell) -> anyhow::Result<PathBuf> {
let build_dir = sh.create_dir("target/xtask/slang-build")?;
Ok(build_dir)
}
pub(crate) fn configure(self: &Self, sh: &Shell) -> anyhow::Result<PathBuf> {
let source_dir = self.assure_source(&sh)?;
let build_dir = self.assure_build(&sh)?;
sh.cmd("cmake")
.args(["-S", source_dir.to_str().unwrap()])
.args(["-B", build_dir.to_str().unwrap()])
.arg("-DCMAKE_BUILD_TYPE=Release")
// https://github.com/shader-slang/slang/issues/5832#issuecomment-2533324982
.arg("-DCMAKE_SKIP_INSTALL_RULES=ON")
.run()
.context("slang-build configure")?;
Ok(PathBuf::from(build_dir))
}
pub(crate) fn build_targets(
self: &Self,
sh: &Shell,
targets: &[&str],
) -> anyhow::Result<PathBuf> {
let build_dir = self.configure(&sh)?;
let cmd = sh
.cmd("cmake")
.args(["--build", build_dir.to_str().unwrap()])
.arg(format!("-j{}", available_parallelism()?));
targets
.iter()
.fold(cmd, |cmd, target| cmd.args(["--target", target]))
.run()?;
Ok(build_dir)
}
}

67
shader-tests/enum.slang Normal file
View File

@ -0,0 +1,67 @@
// enum.slang
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj
//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj
// Confirm that basic `enum` declarations are supported.
enum Color
{
Red,
Green = (1 << 1),
Blue,
}
int test(int val)
{
Color c = Color.Red;
if(val > 1)
{
c = Color.Green;
}
if(c == Color.Red)
{
if((val & 1) != 0)
{
c = Color.Blue;
}
}
switch(c)
{
case Color.Red:
val = 1;
break;
case Color.Green:
val = 2;
break;
case Color.Blue:
val = 3;
break;
default:
val = -1;
break;
}
return (val << 4) + int(c);
}
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
[numthreads(4, 1, 1)]
void computeMain(int3 dispatchThreadID : SV_DispatchThreadID)
{
int tid = dispatchThreadID.x;
int val = int(tid);
val = test(val);
outputBuffer[tid] = val;
}

View File

@ -0,0 +1,4 @@
10
33
22
22

11
shader/hello-world.slang Normal file
View File

@ -0,0 +1,11 @@
StructuredBuffer<float> buffer0;
StructuredBuffer<float> buffer1;
RWStructuredBuffer<float> result;
[shader("compute")]
[numthreads(1,1,1)]
void computeMain(uint3 threadId : SV_DispatchThreadID)
{
uint index = threadId.x;
result[index] = buffer0[index] + buffer1[index];
}