gfx-rs/wgpu
Shader translation
Shader translation is one of the most distinctive parts of wgpu. The user supplies a shader in WGSL, GLSL, SPIR-V, or pre-built naga IR; the runtime needs the shader in whatever language the active backend's driver wants. This page traces the path.
End-to-end flow
graph LR
UserSrc[User shader source<br/>WGSL / GLSL / SPIR-V / naga IR] --> Wgpu[wgpu::Device::create_shader_module]
Wgpu --> Bridge[wgpu-naga-bridge]
Bridge --> Front[naga::front::*]
Front --> Mod[naga::Module]
Mod --> Valid[naga::valid::Validator]
Valid --> Info[ModuleInfo]
Info --> Bridge2[wgpu-naga-bridge]
Bridge2 -->|backend = vulkan| SpvOut[naga::back::spv]
Bridge2 -->|backend = metal| MslOut[naga::back::msl]
Bridge2 -->|backend = dx12| HlslOut[naga::back::hlsl]
Bridge2 -->|backend = gles| GlslOut[naga::back::glsl]
SpvOut -->|SPIR-V| Vk[Vulkan driver]
MslOut -->|MSL source| Mtl[Metal compiler]
HlslOut -->|HLSL source| Dxc[DXC / FXC]
Dxc -->|DXIL / DXBC| Dx12[D3D12 driver]
GlslOut -->|GLSL source| Gl[GL driver]On the WebGPU backend (browser), the flow is much shorter: the WGSL string is passed unchanged to navigator.gpu, and the browser's WebGPU implementation handles validation and translation.
At each step
1. User-supplied source
wgpu::ShaderModuleDescriptor (wgpu/src/api/shader_module.rs) accepts:
Wgsl(Cow<'_, str>)— WGSL source. Default and most common.Glsl { shader, stage, defines }— GLSL source. Requires theglslfeature.SpirV(Cow<'_, [u32]>)— SPIR-V binary. Requires thespirvfeature.Naga(Cow<'_, naga::Module>)— pre-parsed IR. Requires thenaga-irfeature.Dummy(PhantomData)— for builds that omit shader compilation.- Plus a
Passthrough(...)variant for backends that take backend-native shaders directly.
2. Frontend
If the input is source, the relevant naga::front::* parser runs. WGSL has the most polished diagnostics; GLSL and SPIR-V are functional. See crates/naga/frontends.
3. Validator
naga::valid::Validator::validate runs the IR through every checked rule. The Capabilities set is determined by wgpu-naga-bridge from the device's Features. Failed validation surfaces as a WithSpan<ValidationError>; the WGSL frontend's diagnostic formatter renders it with source-position info.
4. Backend code generation
wgpu-naga-bridge picks the right backend based on the active wgpu-hal backend:
- Vulkan →
naga::back::spv. - Metal →
naga::back::msl. - DX12 →
naga::back::hlsl(then DXC compiles HLSL to DXIL insidewgpu-hal/src/dx12/shader_compilation.rs). - GLES →
naga::back::glsl.
Each backend carries a knob like Version::Embedded { version, is_webgl } (GLSL) or ShaderModel::V5_1 (HLSL) so the output matches what the driver actually expects.
5. Pipeline-constant substitution
naga/src/back/pipeline_constants.rs replaces @override values with concrete values just before code emission. This happens once per pipeline (when the RenderPipeline or ComputePipeline is created), not once per shader module. Multiple pipelines built from the same shader can therefore have different override values.
6. Driver compilation
The driver takes over:
- Vulkan:
vkCreateShaderModulevalidates SPIR-V and pre-compiles for the GPU. - Metal:
MTLDevice::newLibraryWithSource:compiles MSL. - DX12: DXC produces DXIL from HLSL; D3D12 then accepts DXIL or DXBC into the pipeline state.
- GL/GLES:
glCompileShader+glLinkProgram, deferred until the program is first used.
What can go wrong
- WGSL not in the spec yet —
naga's WGSL frontend is constantly catching up to the WebGPU/WGSL working draft.README.mdis candid: "thewgpucrate and the version of WGSL it implements will likely differ from what is specified." Bug reports againstnagaare tracked with thenagalabel on the wgpu issue tracker. - GLSL → SPIR-V handoff — the GLSL frontend is more limited than the WGSL one. Compute shaders, subgroup ops, and some atomics are not fully supported.
- HLSL semantics quirks —
naga::back::hlslemits HLSL that DXC then re-compiles. There are edge cases where a user's WGSL is valid, the IR is valid, the HLSL is valid syntactically, but DXC's later checks reject the output. These tend to surface as "shader compilation failed" errors during pipeline creation.WGPU_DX12_COMPILER=fxcmay behave differently thandxchere. - Driver bugs — vendors occasionally miscompile shaders. Workarounds live in the relevant
wgpu-halbackend or innaga's backend (emitting a slightly different but equivalent shader).
Bypassing translation
If you have a backend-native shader you'd rather use directly:
- The
Passthroughvariant ofShaderModuleDescriptorbypasses naga and sends a string straight to the driver. Used when integrating with engines that have their own shader pipelines. Naga(...)skips frontend parsing.
Diagnostics
RUST_LOG=naga=debug,wgpu_core::pipeline=traceshows each translation step.naga(the CLI) parses, validates, and emits in any direction. Useful for reproducing issues without the rest of the stack.Instance::AUTOMATIC_SHADER_FALLBACK(InstanceFlags) letsnagaapply automatic conversions when a user shader is borderline (e.g. interpolation defaults).
See also
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.