- Limit the amount of comments you put in the code to a strict minimum. You should almost never add comments, except sometimes on non-trivial code, function definitions if the arguments aren't self-explanatory, and class definitions and their members.
- Do not use emoji.
- You can test that the code builds by running
cargo build. Don't pass--releaseunless there's a specific need to test a release build, it's much slower. - After making code changes, ensure the code is formatted by using
cargo fmt, linted by usingcargo clippy --tests. If there are no errors, you can usecargo xtask testandcargo xtask cts --backend <backend>to run tests (to fully validate a change, run both). On MacOS, the backend ismetal. On Windows, the backend isdx12. On Linux, the backend isvulkan. - Do not perform commits yourself, ever.
- Use the WebGPU and WGSL specifications as a reference to determine the correct behavior. Do not assume that a behavior is correct just because the CTS expects it.
We maintain a changelog in CHANGELOG.md. Changes should be noted in the changelog if they are user-visible (changes to documented public APIs, significant bug fixes, or new functionality). Changelog descriptions should be concise. If you are not sure whether something should be in the CHANGELOG or you are not sure how to describe the change, ask the user for guidance.
There is some more detailed information about tests in @docs/testing.md.
Each line is a selector that will run multiple subtests. You can run a test with:
cargo xtask cts 'webgpu:selector/path:test:*'For fixing problems, it may be useful to run specific cases. You can get a list of the subtests with:
cargo xtask cts -- --list 'webgpu:selector,path:test:*'Then you can pass individual subtests on the command line as the selector.
To run a suite of CTS tests and keep just the summary at the end:
cargo xtask cts 'webgpu:selector,path:test:*' 2>&1 | grep -E "(Summary|Passed|Failed)" | tail -5To run a suite of tests and keep just the failing tests:
cargo xtask cts 'webgpu:selector,path:test:*' 2>&1 | grep "\[fail\]"We maintain three files listing CTS test selectors that are expected to pass, not pass, or to be entirely skipped. These files are respectively cts_runner/test.lst, cts_runner/fail.lst, and cts_runner/skip.lst.
If you fix a CTS test, add the selector to test.lst. Be aware that the file is not an exhaustive list of passing tests.
CI expects every test in test.lst to pass, so only add suites that have zero failures to test.lst. Do not add any suites that are not 100% pass/skip, even if they are ≥99% passing.
List suites with failures in fail.lst. You can put a comment // xx%
noting the pass rate, especially in cases where the pass rate is high.
List suites that are ≥90% skips in skip.lst
When adding to a lst file, use wildcards to identify the tests with as few lines as possible. In some cases when adding tests it may be possible to combine with existing lines to use a higher level wildcard. Only use a higher level wildcard when all the tests it will match go in the same file. Do not use a higher level wildcard if it would match tests that belong in a different file.
The TypeScript sources for the CTS are under cts/src. There is also generated JavaScript in cts/out. Do not assume that a behavior is correct just because a CTS test expects it. Verify the correct behavior in the WebGPU or WGSL specification.
See docs/big-picture.png for an overview of the system.
The major components are:
-
wgpu-halimplements a backend for each supported graphics API (Vulkan, DX12, Metal, GLES). -
wgpu-coreimplements the WebGPU API, including resource management and validation. It calls the platform graphics APIs viawgpu-hal, and usesnagafor shader translation. -
wgpuis the native Rust API. In addition to providing bindings towgpu-core, thewgpucrate can also be compiled to WASM and built against the "WebGPU" backend, where it uses whatever WebGPU implementation is provided by the WASM environment.wgpuis not used by Deno and Firefox. -
nagais the shader translator. It reads shaders in WGSL, GLSL, or SPIR-V, translates to Naga IR, and then writes shaders in GLSL, HLSL, MSL (Metal Shading Language), SPIR-V, or WGSL. It is responsible for validating that WGSL shaders are valid according to the WGSL language specification. -
wgpu-typescontains some type definitions that are applicable both towgpu-coreand to thewgpu"WebGPU" backend. -
deno_webgpucontains WebGPU bindings for the Deno Javascript runtime. We also use Deno as a test environment for running the WebGPU CTS. Only make a change in the Deno bindings if you are sure that the issue doesn't apply to other clients (Firefox orwgpuRust API). If it does apply to other clients, the issue should probably be fixed inwgpu-core.
For a more detailed discussion of the wgpu architecture, refer to
https://github.com/gfx-rs/wgpu/wiki/Architecture.
The constant evaluator is responsible for evaluating constant expressions at compile time in WGSL/GLSL shaders.
Key Components:
-
Expression Handling (~line 1228): The
try_eval_and_append_implmethod handles different expression types and evaluates them if possible. -
Type Conversions:
cast()(~line 2256): Handles type conversions withExpression::AswhereconvertisSome(width)bitcast()(~line 2449): Handles bit reinterpretation withExpression::AswhereconvertisNone- Key insight: For bitcast, the target width equals the source width (bit-preserving operation)
-
Helper Macros:
gen_component_wise_extractor!: Generates functions for component-wise operations on scalars/vectorscomponent_wise_scalar!,component_wise_float!: Convenience macros for applying operations to each component
-
Borrow Checker Patterns:
- When implementing methods that need to call themselves recursively or make multiple mutable borrows, extract all needed data from
selffields before the recursive calls - Clone vectors before iterating if you need to mutably borrow
selfduring iteration
- When implementing methods that need to call themselves recursively or make multiple mutable borrows, extract all needed data from
Expression::Aswithconvert: Nonerepresents bitcast operations- The validator (
naga/src/valid/expression.rs~line 1132) determines result types by:- Getting source type's scalar
- Updating the
kindto target kind - Keeping the same
widthfor bitcast (no conversion)
This is stuff that Claude wrote for itself. It can probably be improved.
Test Structure:
-
Unit Tests: In the same file as the code being tested
- Example:
naga/src/proc/constant_evaluator.rshas tests in a#[cfg(test)] mod testsblock - Pattern: Create arenas, build expressions, evaluate, assert results
- Example:
-
Snapshot Tests:
- Input files:
naga/tests/in/wgsl/*.wgsl - Output files:
naga/tests/out/wgsl/*.wgsl - Run with:
cargo test -p naga --test naga snapshots::convert_snapshots_wgsl - The output shows how constant expressions are evaluated at compile time
- Input files:
-
Adding Integration Tests:
- Add test WGSL code to
naga/tests/in/wgsl/const-exprs.wgslfor const expression tests - The test automatically parses, validates, and generates output in
naga/tests/out/wgsl/wgsl-const-exprs.wgsl - Verify constant evaluation by checking the output file
- Add test WGSL code to
Running Tests:
# Unit tests only
cargo test -p naga --lib
# Specific test
cargo test -p naga --lib bitcast
# All naga tests (including integration)
cargo test -p naga
# WGSL snapshot tests
cargo test -p naga --test naga snapshots::convert_snapshots_wgslWhen implementing WGSL built-in functions:
- Read the spec carefully: WGSL spec section numbers are usually commented in code (e.g., "17.2.1. bitcast")
- Check parameterization: The spec lists exactly which type combinations are valid
- Don't assume types: For bitcast, only
i32,u32,f32are specified - not 64-bit types - AbstractInt special cases: Some operations have special handling for abstract integers