gfx-rs/wgpu
Architecture
wgpu is a layered system. The top layer is the public Rust or JavaScript API; the bottom layer is the platform's native graphics driver (Vulkan, Metal, D3D12, GL, or the browser's WebGPU). Between them sit two layers of wgpu's own code that implement WebGPU semantics, plus a separate library for shader translation.
There is a canonical block diagram in docs/big-picture.png (and the editable docs/big-picture.xml). The text below describes the same picture.
High-level layering
graph TD
subgraph Clients
App[Native Rust app]
FF[Firefox / Servo]
Deno[Deno runtime]
Web[Web page in a browser]
end
subgraph wgpu_repo[This repository]
Wgpu[wgpu crate<br/>idiomatic Rust API]
DenoBindings[deno_webgpu<br/>JS bindings]
Core[wgpu-core<br/>WebGPU semantics + validation]
Naga[naga<br/>shader translator]
Hal[wgpu-hal<br/>per-API backends]
Types[wgpu-types<br/>shared types]
end
subgraph Drivers
Vk[Vulkan driver]
Mt[Metal driver]
Dx[DX12 driver]
Gl[GL / WebGL2]
Browser[Browser WebGPU]
end
App --> Wgpu
FF --> Core
Deno --> DenoBindings
DenoBindings --> Core
Web --> Browser
Wgpu -.wasm WebGPU backend.-> Browser
Wgpu --> Core
Core --> Naga
Core --> Hal
Hal --> Vk
Hal --> Mt
Hal --> Dx
Hal --> Gl
Wgpu --- Types
Core --- Types
Hal --- TypesThe wgpu crate has two backends of its own (wgpu/src/backend/):
wgpu_core— calls intowgpu-corefor native targets and WebGL2.webgpu— calls into the browser'snavigator.gpuviaweb-syswhen compiled for the web with thewebgpufeature.
There is also a custom backend that lets downstream embedders plug in their own dispatch (wgpu/src/backend/custom.rs), exposed through the custom crate feature.
Layer responsibilities
wgpu (wgpu/src/api/, wgpu/src/backend/)
The user-facing crate. Exposes idiomatic, refcounted Rust types: Instance, Adapter, Device, Queue, Buffer, Texture, CommandEncoder, render and compute passes, etc. Each type lives in its own file under wgpu/src/api/. The handle types are thin wrappers around Arc<dyn DispatchFoo> trait objects defined in wgpu/src/dispatch.rs. The dispatch trait routes calls to one of the three backends (wgpu_core, webgpu, custom).
This crate adds no validation of its own — it is a transport layer. Validation is the responsibility of wgpu-core (or the browser, on the WebGPU backend).
wgpu-core (wgpu-core/src/)
The portable, FFI-shaped implementation of WebGPU. This is what Firefox and Deno actually link against. Responsibilities:
- Resource registry — every public resource (buffers, textures, bind groups, pipelines, ...) gets an
Idfrom a slab-allocated registry (wgpu-core/src/registry.rs,wgpu-core/src/storage.rs,wgpu-core/src/hub.rs). - Validation — checks descriptors, usages, lifetimes, label limits, format compatibility (
wgpu-core/src/validation.rs, plus per-resource validation in each module). - Resource state tracking — tracks buffer/texture usage states across passes and command buffers so it can insert correct barriers (
wgpu-core/src/track/). - Command building — the
CommandEncoderand pass APIs translate WebGPU commands into HAL commands (wgpu-core/src/command/, wheremod.rs,render.rs,compute.rs,bundle.rs,transfer.rs,clear.rs,ray_tracing.rslive). - Submission and lifetime tracking —
wgpu-core/src/device/queue.rsandwgpu-core/src/device/life.rsmanage submissions, fences, and resource cleanup. - Pipelines, bind groups, layouts —
wgpu-core/src/pipeline.rs,wgpu-core/src/binding_model.rs. - Swapchain glue —
wgpu-core/src/present.rs. - Tracing — optional API trace capture (
wgpu-core/src/device/trace.rs,wgpu-core/src/device/trace/). - Indirect-draw validation — a separate compute-shader-based validator for indirect commands (
wgpu-core/src/indirect_validation/).
wgpu-core calls wgpu-hal for everything that touches the GPU and naga for shader translation.
wgpu-hal (wgpu-hal/src/)
A thin, unsafe abstraction over native graphics APIs. The traits live in wgpu-hal/src/lib.rs; one module per backend implements them:
wgpu-hal/src/vulkan/— Vulkan via theashcrate.wgpu-hal/src/metal/— Metal viaobjc2/objc2-metal(no third-party Metal crate; objc2 bindings directly).wgpu-hal/src/dx12/— Direct3D 12 via thewindowscrate.wgpu-hal/src/gles/— OpenGL ES, OpenGL, WebGL2, EGL/WGL, plus emscripten and web shims.wgpu-hal/src/noop/— A backend that does no work; used for trace tests and validation-only tests.
There is also wgpu-hal/src/dynamic/ providing DynInstance/DynDevice trait-object shims so wgpu-core can hold backends without monomorphizing over them, and wgpu-hal/src/auxil/ for shared helpers (DXC compiler glue, format conversions, renderdoc capture, etc.).
wgpu-hal does no validation and no state tracking. It is roughly a 1:1 mapping over the native API's command buffers, descriptor sets / argument buffers, and resources. Errors are limited to "things the user can't anticipate" like out-of-memory and device lost.
naga (naga/src/)
Shader translator. Reads WGSL, GLSL, or SPIR-V. Builds a Naga IR (naga/src/ir/). Validates the IR (naga/src/valid/) against the WGSL specification. Writes out SPIR-V, MSL, HLSL, GLSL, WGSL, or DOT.
graph LR
WGSL[WGSL source] --> Front
GLSL[GLSL source] --> Front
SPV[SPIR-V binary] --> Front
Front[front/<br/>parsers] --> IR[Naga IR<br/>arena-based]
IR --> Compact[compact/<br/>dead-code elimination]
IR --> Valid[valid/<br/>type/handle/function checking]
Valid --> IR
Compact --> IR
IR --> Back[back/<br/>writers]
Back --> SpvOut[SPIR-V]
Back --> MSL[Metal Shading Language]
Back --> HLSL[HLSL]
Back --> GLSLOut[GLSL]
Back --> WGSLOut[WGSL]
Back --> DOT[GraphViz DOT]naga is #![no_std] and #![forbid(unsafe_code)]. It can be used standalone (e.g. via the naga CLI) or inside wgpu-core. The wgpu-naga-bridge crate adapts naga's types to wgpu-core's data flow.
wgpu-types (wgpu-types/src/)
Plain-data structs and enums (Features, Limits, TextureFormat, BufferUsages, Color, ...) shared by all three layers and by downstream consumers. Has no platform code; runs on all targets including wasm.
Languages spoken across the boundary
graph LR
Public["Public API:<br/>Rust handles or<br/>JS objects via deno_webgpu"] --> Ids
Ids["wgpu-core: u64 Ids<br/>(FFI-friendly)"] --> Hal
Hal["wgpu-hal: trait objects<br/>(DynInstance, DynDevice, ...)"] --> Native["Native API:<br/>VkDevice, MTLDevice,<br/>ID3D12Device, GL context"]- The public Rust API uses owned, refcounted handles (
Buffer,Texture, ...) that internally holdArc<dyn DispatchBuffer>etc. wgpu-core's public surface is ID-based andextern "C"-friendly (wgpu-core/src/id.rs,wgpu-core/src/global.rs). This is what Firefox'sgfx/wgpu_bindings/calls.wgpu-haluses Rust trait objects but isunsafe. There is a static dispatch path (vulkan::Api,metal::Api, ...) and a dynamic dispatch path (DynInstance,DynDevice, ...) that letswgpu-corecarry aVec<(Backend, Box<dyn DynInstance>)>.
Where data lives at each layer
| Concern | Layer | Files |
|---|---|---|
| Refcounted handle types | wgpu |
wgpu/src/api/*.rs |
| Backend dispatch | wgpu |
wgpu/src/dispatch.rs, wgpu/src/backend/ |
| Resource registry by ID | wgpu-core |
wgpu-core/src/{hub,registry,storage,id}.rs |
| Validation | wgpu-core |
wgpu-core/src/validation.rs and per-resource *.rs |
| State/usage tracking | wgpu-core |
wgpu-core/src/track/ |
| Lock ranking | wgpu-core |
wgpu-core/src/lock/ |
| Command translation | wgpu-core |
wgpu-core/src/command/ |
| HAL traits | wgpu-hal |
wgpu-hal/src/lib.rs |
| Vulkan backend | wgpu-hal |
wgpu-hal/src/vulkan/ |
| Metal backend | wgpu-hal |
wgpu-hal/src/metal/ |
| DX12 backend | wgpu-hal |
wgpu-hal/src/dx12/ |
| GLES/WebGL backend | wgpu-hal |
wgpu-hal/src/gles/ |
| Shader IR | naga |
naga/src/ir/ |
| Shader frontends | naga |
naga/src/front/{wgsl,glsl,spv}/ |
| Shader backends | naga |
naga/src/back/{spv,msl,hlsl,glsl,wgsl,dot}/ |
| Shader validation | naga |
naga/src/valid/ |
| Constant evaluator | naga |
naga/src/proc/constant_evaluator.rs |
Lifetime of a draw call
sequenceDiagram
participant U as User code
participant W as wgpu (Rust API)
participant C as wgpu-core
participant H as wgpu-hal (Vulkan)
participant V as VkDevice
U->>W: render_pass.draw(0..3, 0..1)
W->>W: dispatch.rs routes to wgpu_core backend
W->>C: render_pass_draw(pass_id, 0, 3, 0, 1)
C->>C: validate (pipeline set? bind groups bound? buffer bindings in range?)
C->>C: track buffer/texture usages
C->>H: encoder.draw(...)
H->>V: vkCmdDraw(cmd_buf, 3, 1, 0, 0)When the encoder is finished and the queue submits the command buffer, wgpu-core flushes its tracker, inserts pipeline barriers via wgpu-hal, and calls into the platform queue.
The naga integration
The wgpu-naga-bridge crate (wgpu-naga-bridge/src/) takes the parsed WGSL/SPIR-V module produced by naga, runs naga's validator with the right Capabilities for the device, and hands the validated module to whichever naga backend matches the active wgpu-hal backend (SPIR-V for Vulkan, MSL for Metal, HLSL for DX12, GLSL for GLES). On the WebGPU backend, the WGSL source is simply passed through to the browser unchanged.
Cross-cutting features
These are explored in features/:
- Shader translation — the WGSL/GLSL/SPIR-V → IR → SPIR-V/MSL/HLSL/GLSL pipeline.
- Cross-platform backends — how a single
wgpuAPI maps onto five very different drivers. - Ray tracing — experimental BLAS/TLAS/
@ray_querysupport. - Mesh shading — experimental task/mesh pipelines.
- API tracing — capturing and replaying API calls via
wgpu-core'sTraceinfrastructure and theplayercrate.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.