Documentation
¶
Overview ¶
Package naga provides a Pure Go shader compiler.
naga compiles WGSL (WebGPU Shading Language) source code to multiple output formats:
- SPIR-V — Binary format for Vulkan
- MSL — Metal Shading Language for macOS/iOS
- GLSL — OpenGL Shading Language for OpenGL 3.3+, ES 3.0+
- HLSL — High Level Shading Language for DirectX
- DXIL — DirectX Intermediate Language for Direct3D 12
This package is the one-call path from WGSL to SPIR-V, plus pipeline constants (ProcessOverrides) and module compaction (Compact). Each language has its own package: a frontend's Parse (wgsl.Parse) gives an IR module, valid.Validate checks it, and a backend's Compile (spirv, msl, glsl, hlsl, dxil) writes it.
Example usage (SPIR-V):
source := `
@vertex
fn main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}
`
spirv, err := naga.Compile(source)
if err != nil {
log.Fatal(err)
}
For MSL output:
module, _, err := wgsl.Parse(source, wgsl.ParseOptions{})
...
if _, err := valid.Validate(module, valid.Options{}); err != nil { ... }
mslCode, info, err := msl.Compile(module, msl.Options{})
Concurrency ¶
Every exported function is safe for concurrent use. ProcessOverrides never modifies its input module; its result may share unmodified parts of it. Compact is the one function that modifies the module it is given, in place: no other goroutine may use that module while it runs.
Example (Backends) ¶
Parse, validate with the device's capabilities, then write any backend.
package main
import (
"errors"
"fmt"
"github.com/gogpu/naga"
"github.com/gogpu/naga/dxil"
"github.com/gogpu/naga/glsl"
"github.com/gogpu/naga/hlsl"
"github.com/gogpu/naga/msl"
"github.com/gogpu/naga/spirv"
"github.com/gogpu/naga/valid"
"github.com/gogpu/naga/wgsl"
)
const exampleShader = `
override gain: f32 = 1.0;
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
data[id.x] = data[id.x] * gain;
}
`
func main() {
module, _, err := wgsl.Parse(exampleShader, wgsl.ParseOptions{})
if err != nil {
var pe *wgsl.ParseError
if errors.As(err, &pe) {
fmt.Println(pe.Format(exampleShader, "shader.wgsl"))
}
return
}
info, err := valid.Validate(module, valid.Options{Capabilities: valid.CapShaderFloat16})
if err != nil {
fmt.Println(err)
return
}
// Backends take a module without overrides: give them their values first.
module, _, err = naga.ProcessOverrides(module, info, naga.OverrideOptions{})
if err != nil {
fmt.Println(err)
return
}
_, _, errSPIRV := spirv.Compile(module, spirv.Options{})
_, _, errMSL := msl.Compile(module, msl.Options{})
_, _, errGLSL := glsl.Compile(module, glsl.Options{LangVersion: glsl.Version450})
_, _, errHLSL := hlsl.Compile(module, hlsl.Options{})
_, _, errDXIL := dxil.Compile(module, dxil.Options{})
fmt.Println(errors.Join(errSPIRV, errMSL, errGLSL, errHLSL, errDXIL))
}
Output: <nil>
Index ¶
- Variables
- func Compact(module *ir.Module, keep KeepUnused)
- func Compile(source string) ([]byte, error)
- func CompileWithOptions(source string, opts CompileOptions) ([]byte, error)
- func ProcessOverrides(module *ir.Module, info valid.ModuleInfo, opts OverrideOptions) (*ir.Module, valid.ModuleInfo, error)
- type CompileOptions
- type KeepUnused
- type OverrideOptions
- type PipelineConstantError
- type PipelineConstants
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrOverrideNotFound: a key names no override of the module. ErrOverrideNotFound = overrides.ErrNotFound // ErrOverrideMissingValue: an override an entry point uses has no value // and no default. ErrOverrideMissingValue = overrides.ErrMissingValue // ErrOverrideValueNotFinite: NaN or an infinity for a numeric override. ErrOverrideValueNotFinite = overrides.ErrValueNotFinite // ErrOverrideValueOutOfRange: the value does not fit the override's type. ErrOverrideValueOutOfRange = overrides.ErrValueOutOfRange // ErrNegativeWorkgroupSize: a workgroup size given by an override is not // positive. ErrNegativeWorkgroupSize = overrides.ErrNegativeWorkgroupSize // ErrNegativeMeshOutputMax: a mesh output limit given by an override is // negative. ErrNegativeMeshOutputMax = overrides.ErrNegativeMeshOutputMax )
Pipeline-constant errors.
Functions ¶
func Compact ¶ added in v0.21.0
func Compact(module *ir.Module, keep KeepUnused)
Compact removes the objects module does not use and renumbers the handles of what is left, as Rust naga's compact::compact does. module must be valid.
With either keep value it removes the function expressions nothing refers to, the constants, overrides and global expressions nothing uses (named constants of a concrete type always stay), the abstract types and the anonymous types nothing refers to any more. With KeepUnusedNo it first removes the global variables and functions no entry point reaches, and the named overrides nothing uses. Entry points, special types and named types always stay; Rust also removes an unused named type under KeepUnused::No.
Compact modifies module in place: nothing else may read or write module while it runs, and handles taken from module before the call are not valid after it. Calls on different modules may run concurrently.
func Compile ¶
Compile compiles WGSL source code to SPIR-V binary using default options.
Example ¶
Compile WGSL to SPIR-V with the safe defaults.
package main
import (
"fmt"
"github.com/gogpu/naga"
)
const exampleShader = `
override gain: f32 = 1.0;
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
data[id.x] = data[id.x] * gain;
}
`
func main() {
spirvBytes, err := naga.Compile(exampleShader)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(len(spirvBytes) > 0)
}
Output: true
func CompileWithOptions ¶
func CompileWithOptions(source string, opts CompileOptions) ([]byte, error)
CompileWithOptions compiles WGSL source code to SPIR-V binary with custom options.
The compilation pipeline is:
- Parse WGSL to IR (wgsl.Parse); a *wgsl.ParseError is returned wrapped, with its line and column
- Validate IR (if enabled)
- Replace overrides by their defaults (ProcessOverrides with no pipeline constants), as Rust naga's CLI does; an override without a default is an error. For pipeline constants use wgsl.Parse, ProcessOverrides and a backend.
- Generate SPIR-V binary
func ProcessOverrides ¶ added in v0.20.1
func ProcessOverrides(module *ir.Module, info valid.ModuleInfo, opts OverrideOptions) (*ir.Module, valid.ModuleInfo, error)
ProcessOverrides returns module with every override expression replaced by a constant holding its pipeline value or default, every expression that becomes constant evaluated, and workgroup sizes given by overrides resolved — Rust naga's back::pipeline_constants::process_overrides. Call it before a backend; naga.Compile calls it with the defaults.
module is never modified, and ProcessOverrides may be called concurrently on the same module. The result may be module itself when there is nothing to do (no overrides, and no EntryPoint or at most one entry point); treat it as read-only. Handles in the result are not stable relative to module.
A module produced by the WGSL frontend with no overrides (len(Overrides) == 0) has no override expressions, override workgroup sizes or override-sized arrays and needs no processing, but call ProcessOverrides anyway when Constants is not empty: a key that names no override is an error (ErrOverrideNotFound).
With EntryPoint, globals the entry point does not use are removed. A backend that numbers resources by their position in the module (MSL without msl.Options.PerEntryPointMap) can then give them other slots.
The result keeps the overrides arena, with each initializer evaluated, and override-sized arrays stay pending (ir.ArraySize.Resolve sizes them; backends do), as in Rust. With EntryPoint the selected entry point is EntryPoints[0]. Processing a processed module again with other constants is not supported: process the module from the frontend for every pipeline.
The caller MUST have validated module first, with valid.Validate and the device's own valid.Options, and info is that validation's ModuleInfo: capabilities are gated there and nowhere else. When there is nothing to do, module and info are returned as they are, unvalidated. Otherwise the processed module is validated again, as Rust's revalidate does after substitution (validate_resolved_overrides): with every capability allowed, so it re-checks the structure but cannot catch a capability the device lacks. Its new valid.ModuleInfo is returned. A backend never validates.
Errors: a *PipelineConstantError for a constant (errors.Is with ErrOverrideNotFound, ErrOverrideMissingValue, ErrOverrideValueNotFinite, ErrOverrideValueOutOfRange); backend.ErrEntryPointNotFound; ErrNegativeWorkgroupSize; ErrNegativeMeshOutputMax; an evaluation error of an expression that becomes constant (for example a division by zero after substitution); or an invalid processed module. Keys are checked in sorted order, so the same input reports the same key.
Example ¶
Give overrides their values per pipeline, then compile.
package main
import (
"fmt"
"github.com/gogpu/naga"
"github.com/gogpu/naga/backend"
"github.com/gogpu/naga/ir"
"github.com/gogpu/naga/msl"
"github.com/gogpu/naga/valid"
"github.com/gogpu/naga/wgsl"
)
const exampleShader = `
override gain: f32 = 1.0;
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
data[id.x] = data[id.x] * gain;
}
`
func main() {
module, _, err := wgsl.Parse(exampleShader, wgsl.ParseOptions{})
if err != nil {
fmt.Println(err)
return
}
info, err := valid.Validate(module, valid.Options{})
if err != nil {
fmt.Println(err)
return
}
pipelineModule, _, err := naga.ProcessOverrides(module, info, naga.OverrideOptions{
Constants: naga.PipelineConstants{"gain": 1.5},
EntryPoint: &backend.EntryPointSelector{Stage: ir.StageCompute, Name: "main"},
})
if err != nil {
fmt.Println(err)
return
}
code, _, err := msl.Compile(pipelineModule, msl.Options{})
fmt.Println(err == nil && len(code) > 0)
}
Output: true
Types ¶
type CompileOptions ¶
type CompileOptions struct {
// SPIRV is the SPIR-V backend's options, all of them. Its zero value is
// the safe set: SPIR-V 1.0, Restrict bounds checks, bounded loops,
// workgroup memory zeroed, every binding required. A shader that needs
// a newer SPIR-V version (subgroup operations need 1.3) is an error
// until SPIRV.Version gives one; the backend never raises it.
SPIRV spirv.Options
// Capabilities is what the IR validator allows beyond core WebGPU: the
// zero value rejects every optional feature (f64, i64, u64, f16,
// subgroups, 64-bit and f32 atomics, ray queries, mesh shaders, binding
// arrays, ...), as Rust naga's default does. Enable one with its
// valid.Cap* constant, for example [valid.CapShaderFloat16] or
// [valid.CapSubgroup], or [valid.CapAll] to permit everything. The
// subgroup stages and operations are derived from it as
// [valid.Options] documents.
Capabilities valid.Capabilities
// SkipValidation compiles the module without validating it first. The
// zero value validates, as Rust naga's CLI does. A module with overrides
// is still validated after they are replaced, with every capability (as
// ProcessOverrides always does); one without is not validated at all.
SkipValidation bool
}
CompileOptions configures shader compilation.
func DefaultOptions ¶
func DefaultOptions() CompileOptions
DefaultOptions returns the zero CompileOptions, the safe defaults.
type KeepUnused ¶ added in v0.21.0
type KeepUnused bool
KeepUnused selects whether Compact keeps the functions, global variables and named overrides nothing uses, as Rust naga's compact::KeepUnused.
const ( // KeepUnusedNo removes every function and global variable no entry point // reaches and every override nothing uses (Rust KeepUnused::No), as // pipeline-constant processing needs: an override no entry point uses // needs no value. KeepUnusedNo KeepUnused = false // KeepUnusedYes keeps every function, global variable and named override // (Rust KeepUnused::Yes), as after lowering. KeepUnusedYes KeepUnused = true )
type OverrideOptions ¶ added in v0.20.1
type OverrideOptions struct {
// Constants are the pipeline-constant values.
Constants PipelineConstants
// EntryPoint, if not nil, keeps only that entry point; only overrides it
// uses need a value.
EntryPoint *backend.EntryPointSelector
}
OverrideOptions configure ProcessOverrides. The zero value processes every entry point with no pipeline constants: every override takes its default.
type PipelineConstantError ¶ added in v0.20.1
type PipelineConstantError struct {
Key string // the pipeline-constant key, or the override's identifier string
Err error
}
PipelineConstantError is an error about one pipeline constant or override (Rust naga's PipelineConstantError). Err is one of the ErrOverride* sentinels; Error is Rust's message.
func (*PipelineConstantError) Error ¶ added in v0.20.1
func (e *PipelineConstantError) Error() string
func (*PipelineConstantError) Unwrap ¶ added in v0.20.1
func (e *PipelineConstantError) Unwrap() error
Unwrap returns Err, for errors.Is.
type PipelineConstants ¶ added in v0.20.1
PipelineConstants are the values of pipeline-overridable constants (WebGPU GPUProgrammableStage.constants). A key is an override's @id as a decimal string, or its name if it has no @id; keys are compared exactly, as WGSL identifiers.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package backend holds the types that every naga backend shares: the bounds-check policies, the workgroup zero-initialization mode, the entry-point selector, the frag_depth clamp, the DirectX shader model and the error categories a caller can branch on with errors.Is.
|
Package backend holds the types that every naga backend shares: the bounds-check policies, the workgroup zero-initialization mode, the entry-point selector, the frag_depth clamp, the DirectX shader model and the error categories a caller can branch on with errors.Is. |
|
cmd
|
|
|
dxilval
command
Command dxilval validates DXIL containers using Microsoft's IDxcValidator.
|
Command dxilval validates DXIL containers using Microsoft's IDxcValidator. |
|
dxilval/internal/run
Package run implements the dxilval CLI logic.
|
Package run implements the dxilval CLI logic. |
|
nagac
command
Command nagac is the naga shader compiler CLI.
|
Command nagac is the naga shader compiler CLI. |
|
spvdis
command
spvdis - SPIR-V disassembler Generates valid .spvasm text format
|
spvdis - SPIR-V disassembler Generates valid .spvasm text format |
|
texture_compile
command
|
|
|
Package dxil implements a DXIL (DirectX Intermediate Language) backend for the naga shader compiler.
|
Package dxil implements a DXIL (DirectX Intermediate Language) backend for the naga shader compiler. |
|
internal/bitcode
Package bitcode implements a bit-level writer for LLVM 3.7 bitcode format.
|
Package bitcode implements a bit-level writer for LLVM 3.7 bitcode format. |
|
internal/container
Package container implements the DXBC container format used to wrap DXIL shader bitcode.
|
Package container implements the DXBC container format used to wrap DXIL shader bitcode. |
|
internal/emit
Package emit implements naga IR to DXIL module lowering.
|
Package emit implements naga IR to DXIL module lowering. |
|
internal/module
Package module provides an in-memory representation of a DXIL module.
|
Package module provides an in-memory representation of a DXIL module. |
|
internal/passes/dce
Package dce implements dead code elimination for DXIL shader functions.
|
Package dce implements dead code elimination for DXIL shader functions. |
|
internal/passes/mem2reg
Package mem2reg promotes function-scope local variables of scalar type to SSA values, eliminating the corresponding alloca / load / store triples that the DXIL emitter would otherwise produce.
|
Package mem2reg promotes function-scope local variables of scalar type to SSA values, eliminating the corresponding alloca / load / store triples that the DXIL emitter would otherwise produce. |
|
internal/passes/sroa
Package sroa implements Scalar Replacement of Aggregates for DXIL emit.
|
Package sroa implements Scalar Replacement of Aggregates for DXIL emit. |
|
internal/viewid
Package viewid computes input→output dataflow dependencies for graphics entry points, producing the data that populates DXIL's `dx.viewIdState` metadata (ComputeViewIdState.cpp format) and the PSV0 dependency table (PSVDependencyTable layout).
|
Package viewid computes input→output dataflow dependencies for graphics entry points, producing the data that populates DXIL's `dx.viewIdState` metadata (ComputeViewIdState.cpp format) and the PSV0 dependency table (PSVDependencyTable layout). |
|
Package glsl provides a GLSL (OpenGL Shading Language) backend for naga.
|
Package glsl provides a GLSL (OpenGL Shading Language) backend for naga. |
|
Package hlsl provides HLSL (High-Level Shading Language) code generation from the naga intermediate representation.
|
Package hlsl provides HLSL (High-Level Shading Language) code generation from the naga intermediate representation. |
|
internal/codegen
Package hlsl implements HLSL expression generation for all IR expression types.
|
Package hlsl implements HLSL expression generation for all IR expression types. |
|
internal
|
|
|
cmd/corpussync
command
Command corpussync maintains the Rust naga test corpus vendored under snapshot/testdata (ADR-006).
|
Command corpussync maintains the Rust naga test corpus vendored under snapshot/testdata (ADR-006). |
|
consteval
Package consteval evaluates WGSL const-expressions: the shader-creation-time evaluation that the WGSL specification requires for const declarations and that naga also applies to constant operands in function bodies.
|
Package consteval evaluates WGSL const-expressions: the shader-creation-time evaluation that the WGSL specification requires for const declarations and that naga also applies to constant operands in function bodies. |
|
d3d
Package d3d holds cross-backend constants and helpers shared between naga's text backends (HLSL) and binary backends (DXIL) that both target the D3D ecosystem.
|
Package d3d holds cross-backend constants and helpers shared between naga's text backends (HLSL) and binary backends (DXIL) that both target the D3D ecosystem. |
|
dxcvalidator
Package dxcvalidator wraps Microsoft's IDxcValidator (dxil.dll) so naga can run real DXIL validation against generated containers from Pure Go.
|
Package dxcvalidator wraps Microsoft's IDxcValidator (dxil.dll) so naga can run real DXIL validation against generated containers from Pure Go. |
|
dxcvalidator/bitcheck
Package bitcheck implements a minimal LLVM 3.7 bitstream reader that walks a DXIL container far enough to verify the `!dx.entryPoints` named metadata is well-formed — specifically that every entry-point tuple has a non-null function reference in operand 0.
|
Package bitcheck implements a minimal LLVM 3.7 bitstream reader that walks a DXIL container far enough to verify the `!dx.entryPoints` named metadata is well-formed — specifically that every entry-point tuple has a non-null function reference in operand 0. |
|
entrypoint
Package entrypoint selects the entry point a backend writes, the meaning of every backend's Options.EntryPoint (backend.EntryPointSelector).
|
Package entrypoint selects the entry point a backend writes, the meaning of every backend's Options.EntryPoint (backend.EntryPointSelector). |
|
irutil
Package irutil holds the IR helpers and passes that naga's own frontends, backends and pipeline-constant processing share and that are not part of the public ir package: ir keeps the data model, validation, type resolution and the few helpers a frontend or backend outside naga needs (ADR-010 B7).
|
Package irutil holds the IR helpers and passes that naga's own frontends, backends and pipeline-constant processing share and that are not part of the public ir package: ir keeps the data model, validation, type resolution and the few helpers a frontend or backend outside naga needs (ADR-010 B7). |
|
overrides
Package overrides replaces pipeline-overridable constants by their values: a port of Rust naga's back::pipeline_constants::process_overrides on the shared constant evaluator (ADR-008).
|
Package overrides replaces pipeline-overridable constants by their values: a port of Rust naga's back::pipeline_constants::process_overrides on the shared constant evaluator (ADR-008). |
|
readback
Package readback reads the GPU readback corpus under testdata/readback: small compute shaders with the values a GPU must write when it runs them.
|
Package readback reads the GPU readback corpus under testdata/readback: small compute shaders with the values a GPU must write when it runs them. |
|
registry
Package registry provides type deduplication for the naga IR.
|
Package registry provides type deduplication for the naga IR. |
|
ssa
Package ssa holds the two expression kinds the DXIL backend adds to a function when it promotes local variables to SSA values: Alias and Phi.
|
Package ssa holds the two expression kinds the DXIL backend adds to a function when it promotes local variables to SSA values: Alias and Phi. |
|
testcorpus
Package testcorpus records and verifies the provenance of the test corpus under snapshot/testdata (ADR-006).
|
Package testcorpus records and verifies the provenance of the test corpus under snapshot/testdata (ADR-006). |
|
testtools
Package testtools gives tests one policy for external tools (spirv-val, spirv-dis, dxc, ...), in the spirit of Go's internal/testenv.
|
Package testtools gives tests one policy for external tools (spirv-val, spirv-dis, dxc, ...), in the spirit of Go's internal/testenv. |
|
textutil
Package textutil provides shared text writing utilities for naga codegen backends.
|
Package textutil provides shared text writing utilities for naga codegen backends. |
|
typifier
Package typifier types the expressions of an IR function: Rust naga's Typifier (front/mod.rs) with the rules of proc::ResolveContext::resolve (proc/typifier.rs).
|
Package typifier types the expressions of an IR function: Rust naga's Typifier (front/mod.rs) with the rules of proc::ResolveContext::resolve (proc/typifier.rs). |
|
unsupported
Package unsupported builds the backends' refusals: errors that wrap backend.ErrUnsupported while keeping their message as written.
|
Package unsupported builds the backends' refusals: errors that wrap backend.ErrUnsupported while keeping their message as written. |
|
Package ir defines the intermediate representation for naga.
|
Package ir defines the intermediate representation for naga. |
|
Package msl implements Metal Shading Language (MSL) code generation for naga.
|
Package msl implements Metal Shading Language (MSL) code generation for naga. |
|
Package spirv provides SPIR-V code generation from naga IR.
|
Package spirv provides SPIR-V code generation from naga IR. |
|
internal/codegen
Package codegen implements SPIR-V code generation from naga IR.
|
Package codegen implements SPIR-V code generation from naga IR. |
|
Package valid validates an IR module: Rust naga's valid module.
|
Package valid validates an IR module: Rust naga's valid module. |
|
Package wgsl is the WGSL (WebGPU Shading Language) frontend: Parse turns WGSL source into an IR module, as Rust naga's front::wgsl.
|
Package wgsl is the WGSL (WebGPU Shading Language) frontend: Parse turns WGSL source into an IR module, as Rust naga's front::wgsl. |