Crate wesl

Source
Expand description

§WESL: A Community Standard for Enhanced WGSL

This is the crate for all your WESL needs.

See also the standalone CLI.

§Basic Usage

See Wesl for an overview of the high-level API.

let compiler = Wesl::new("src/shaders");

// compile a WESL file to a WGSL string
let wgsl_str = compiler
    .compile(&"package::main".parse().unwrap())
    .inspect_err(|e| eprintln!("WESL error: {e}")) // pretty errors with `display()`
    .unwrap()
    .to_string();

§Usage in build.rs

In your Rust project you probably want to have your WESL code converted automatically to a WGSL string at build-time, unless your WGSL code must be assembled at runtime.

Add this crate to your build dependencies in Cargo.toml:

[build-dependencies]
wesl = "0.1"

Create the build.rs file with the following content:

fn main() {
    Wesl::new("src/shaders")
        .build_artifact(&"package::main".parse().unwrap(), "my_shader");
}

Include the compiled WGSL string in your code:

let module = device.create_shader_module(ShaderModuleDescriptor {
    label: Some("my_shader"),
    source: ShaderSource::Wgsl(include_wesl!("my_shader")),
});

§Write shaders inline with the quote_module macro

The quote feature flag provides the quote_*! macros which let one write WGSL shaders directly in source code. This has a few advantages:

  • Like quote, it supports local variable injection. This can be used e.g. to customize a shader module at runtime.
  • The module is parsed at build-time, and syntax errors will be reported at the right location in the macro invocation.
  • WGSL and Rust have a similar syntax. Your Rust syntax highlighter will also highlight injected WGSL code.
use wesl::syntax::*; // this is necessary for the quote_module macro

// this i64 value is computed at runtime and injected into the shader.
let num_iterations = 8i64;

// the following variable has type `TranslationUnit`.
let wgsl = wesl::quote_module! {
    @fragment
    fn fs_main(@location(0) in_color: vec4<f32>) -> @location(0) vec4<f32> {
        for (let i = 0; i < #num_iterations; i++) {
            // ...
        }
        return in_color;
    }
};

One can inject variables into the following places by prefixing the name with a # symbol:

Code locationInjected typeIndirectly supported injection type with Into
name of a global declarationGlobalDeclarationDeclaration TypeAlias Struct Function ConstAssert
name of a struct memberStructMember
name of an attribute, after @AttributeBuiltinValue InterpolateAttribute WorkgroupSizeAttribute TypeConstraint CustomAttribute
type or identifier expressionExpressionLiteralExpression ParenthesizedExpression NamedComponentExpression IndexingExpression UnaryExpression BinaryExpression FunctionCallExpression TypeOrIdentifierExpression and transitively: bool i64 (AbstractInt) f64 (AbstractFloat) i32 u32 f32 Ident
name of an attribute preceding and empty block statementStatementCompoundStatement AssignmentStatement IncrementStatement DecrementStatement IfStatement SwitchStatement LoopStatement ForStatement WhileStatement BreakStatement ContinueStatement ReturnStatement DiscardStatement FunctionCallStatement ConstAssertStatement DeclarationStatement
use wesl::syntax::*; // this is necessary for the quote_module macro

let inject_struct = Struct::new(Ident::new("mystruct".to_string()));
let inject_func = Function::new(Ident::new("myfunc".to_string()));
let inject_stmt = Statement::Void;
let inject_expr = 1f32;
let wgsl = wesl::quote_module! {
    struct #inject_struct { dummy: u32 } // structs cannot be empty
    fn #inject_func() {}
    fn foo() {
        @#inject_stmt {}
        let x: f32 = #inject_expr;
    }
};

§Evaluating const-expressions

This is an advanced and experimental feature. wesl-rs supports evaluation and execution of WESL code with the eval feature flag. Early evaluation (in particular of const-expressions) helps developers to catch bugs early by improving the validation and error reporting capabilities of WESL. Full evaluation of const-expressions can be enabled with the lower compiler option.

Additionally, the eval feature adds support for user-defined @const attributes on functions, which allows one to precompute data ahead of time, and ensure that code has no runtime dependencies.

The eval/exec implementation is tested with the WebGPU Conformance Test Suite.

// ...standalone expression
let wgsl_expr = eval_str("abs(3 - 5)").unwrap().to_string();
assert_eq!(wgsl_expr, "2");

// ...expression using declarations in a WESL file
let source = "const my_const = 4; @const fn my_fn(v: u32) -> u32 { return v * 10; }";
let wgsl_expr = compiler
    .compile(&"package::source".parse().unwrap()).unwrap()
    .eval("my_fn(my_const) + 2").unwrap()
    .to_string();
assert_eq!(wgsl_expr, "42u");

§Features

namedescriptionStatus/Specification
genericsuser-defined type-generators and generic functionsexperimental
packagecreate shader libraries published to crates.ioexperimental
evalexecute shader code on the CPU and @const attributeexperimental
naga_extenable all Naga/WGPU extensionsexperimental
serdederive Serialize and Deserialize for syntax nodes

Re-exports§

pub use eval::Eval;eval
pub use eval::EvalError;eval
pub use eval::Exec;eval
pub use eval::Inputs;eval
pub use eval::exec_entrypoint;eval

Modules§

evaleval
syntax
A syntax tree for WGSL and WESL files. The root of the tree is TranslationUnit.

Macros§

include_wesl
Include a WGSL file compiled with Wesl::build_artifact as a string.
query
query_mut
quote_declaration
quote_directive
quote_expression
quote_import
quote_literal
quote_module
quote_statement
wesl_pkg
Include a generated package.

Structs§

BasicSourceMap
Basic implementation of SourceMap.
CacheMangler
A mangler that remembers and can unmangle.
CompileOptions
Compilation options. Used in compile and Wesl::set_options.
CompileResult
The result of Wesl::compile.
Diagnostic
Error diagnostics. Display user-friendly error snippets with Display.
EscapeMangler
A mangler that replaces :: with _ and prefixes components with the number of _ they contain. e.g. foo::bar_baz item => foo__1bar_baz_item
EvalResulteval
The result of CompileResult::eval.
ExecResulteval
The result of CompileResult::exec.
Features
Toggle conditional compilation feature flags.
FileResolver
A resolver that looks for files in the filesystem.
HashMangler
A mangler that hashes the module path. e.g. foo::bar::baz item => item_32938483840293402930392
ModulePath
NoMangler
A mangler that just returns the identifier as-is (no mangling). e.g. foo::bar::baz item => item
NoResolver
A resolver that never resolves anything.
NoSourceMap
This SourceMap implementation simply does nothing and returns None.
Pkg
PkgBuilderpackage
A builder that generates code for WESL packages.
PkgModule
The type implemented by external packages.
PkgResolver
A resolver that only resolves module paths that refer to modules in external packages.
Preprocessor
A WESL module preprocessor.
Router
A resolver that can dispatch imports to several sub-resolvers based on the import path prefix.
SourceMapper
Generate a SourceMap by keeping track of loaded files and mangled identifiers.
StandardResolver
The resolver that implements the WESL standard.
UnicodeMangler
A mangler that uses cryptic unicode symbols that look like :, < and > e.g. foo::bar::baz array<f32,2> => foo::bar::baz::arrayᐸf32ˏ2ᐳ
VirtualResolver
A resolver that resolves in-memory modules added with Self::add_module.
Wesl
The WESL compiler high-level API.

Enums§

CondCompError
Conditional translation error.
Error
Any WESL error.
Feature
Set the behavior for a feature flag during conditional translation.
GenericsErrorgenerics
Generics error (experimental)
ImportError
Error produced during import resolution.
ManglerKind
Mangling scheme. Used in Wesl::set_mangler.
ResolveError
Error produced by module resolution.
ValidateError
WESL or WGSL Validation error.

Traits§

Mangler
A name mangler is responsible for renaming import-qualified identifiers into valid WGSL identifiers.
Resolver
A Resolver implements the module resolution algorithm: it returns a module contents associated with a module path.
SourceMap
A SourceMap is a lookup from compiled WGSL to source WESL. It translates a mangled name into a module path and declaration name.
SyntaxUtil

Functions§

compile
Low-level version of Wesl::compile. To get a source map, use compile_sourcemap instead.
compile_sourcemap
Like compile, but provides better error diagnostics and returns the sourcemap.
emit_rerun_if_changed
evaleval
Low-level version of eval_str.
eval_streval
Evaluate a const-expression.
execeval
Low-level version of CompileResult::exec.
lower
Performs conversions on the final syntax tree to make it more compatible with WGSL implementations like Naga, catch errors early and perform optimizations.
validate_wesl
Validate an intermediate WESL module.
validate_wgsl
Validate the final output (valid WGSL).