Open-Source Wikis

/

wgpu

/

Crates

/

wgpu-core

gfx-rs/wgpu

wgpu-core

Active contributors: Andy Leiserson, Erich Gubler, Connor Fitzgerald, teoxoy, Inner Daemons

wgpu-core (wgpu-core/) is the portable, FFI-friendly implementation of WebGPU. It implements the WebGPU specification's semantics: validation, resource state tracking, command translation, submission, lifetime management. It is what Firefox and Deno actually link against; the wgpu crate is a friendlier Rust facade over it.

Purpose

  • Implement WebGPU spec semantics on top of the unsafe wgpu-hal traits.
  • Validate every descriptor and every command before it reaches the driver.
  • Track resource usage states across pass boundaries to insert pipeline barriers correctly.
  • Provide an ID-based public API suitable for FFI (Firefox uses C bindings; Deno uses Rust + Deno's own FFI).
  • Offer optional API tracing and replay (Trace infrastructure) for crash repros and regression testing.

Directory layout

wgpu-core/
├── Cargo.toml
├── README.md
├── build.rs
├── platform-deps/                  per-target glue (apple, wasm, emscripten, win/linux/android)
└── src/
    ├── lib.rs                       crate root
    ├── as_hal.rs                    "convert this id to a hal handle" trait
    ├── binding_model.rs             BindGroup, BindGroupLayout, PipelineLayout (51 KB)
    ├── command/                     CommandEncoder + pass implementations
    │   ├── mod.rs                   ~76 KB main implementation
    │   ├── render.rs                render-pass implementation (~140 KB)
    │   ├── compute.rs               compute-pass (~50 KB)
    │   ├── bundle.rs                render bundles (~63 KB)
    │   ├── ray_tracing.rs           BLAS/TLAS commands (~52 KB)
    │   ├── transfer.rs              copy commands (~57 KB)
    │   ├── clear.rs                 clear commands
    │   └── ...
    ├── conv.rs                      type conversions to hal types
    ├── device/                      Device + Queue + lifetime
    │   ├── mod.rs
    │   ├── resource.rs              Device implementation (~210 KB)
    │   ├── queue.rs                 Queue (~78 KB)
    │   ├── global.rs                Global FFI surface (~76 KB)
    │   ├── life.rs                  lifetime tracker
    │   ├── trace.rs / trace/        API trace recording
    │   └── ...
    ├── error.rs                     top-level error types
    ├── global.rs                    Global type wrapping the Hub
    ├── hub.rs                       per-device resource hub
    ├── id.rs                        Id, Marker
    ├── identity.rs                  identity management
    ├── indirect_validation/         indirect-draw validation pipeline
    ├── init_tracker/                track which buffer ranges are initialized
    ├── instance.rs                  Instance, Adapter
    ├── limits.rs                    limit checking
    ├── lock/                        ranked lock helpers
    ├── pipeline.rs                  shader/pipeline types
    ├── pipeline_cache.rs            persistent pipeline cache
    ├── pool.rs                      generic dedup cache
    ├── present.rs                   surface acquire/present
    ├── ray_tracing.rs               core ray-tracing types
    ├── registry.rs                  typed resource registry
    ├── resource.rs                  Buffer, Texture, Sampler, ... (~91 KB)
    ├── snatch.rs                    "snatch" cell
    ├── storage.rs                   slot-based storage
    ├── timestamp_normalization/     normalize HW timestamps
    ├── track/                       state-tracking machinery
    ├── validation.rs                shader binding validation (~85 KB)
    ├── validation/                  helpers
    └── weak_vec.rs

wgpu-core/src/device/resource.rs (210 KB, the largest file in wgpu-core) is the canonical place to look when you want to know "what does device.create_X do?". wgpu-core/src/device/global.rs (76 KB) is the FFI surface — every public function on Global.

Key abstractions

Type / module File Purpose
Global wgpu-core/src/global.rs Top-level container. Every FFI entry point is a method on it.
Hub wgpu-core/src/hub.rs Set of registries: buffers, textures, bind groups, pipelines, queries, ...
Registry<T> wgpu-core/src/registry.rs Typed accessor over a Storage<T, M>.
Storage<T, M> wgpu-core/src/storage.rs Slot-based store keyed by Id<M>. Recycles indices.
Id<M> wgpu-core/src/id.rs 64-bit handle: index + epoch + backend bits.
Device wgpu-core/src/device/resource.rs Logical GPU; owner of every resource it created.
Queue wgpu-core/src/device/queue.rs Submission and pending-write management.
LifetimeTracker wgpu-core/src/device/life.rs Per-submission resource cleanup.
Buffer, Texture, etc. wgpu-core/src/resource.rs Tracked resource structs.
BindGroup, BindGroupLayout, PipelineLayout wgpu-core/src/binding_model.rs Bind group machinery.
RenderPipeline, ComputePipeline, ShaderModule wgpu-core/src/pipeline.rs Pipeline objects.
Trackers wgpu-core/src/track/ BufferTracker, TextureTracker, usage scopes.
Trace wgpu-core/src/device/trace.rs API recording.

How it works

sequenceDiagram
    participant User as User (wgpu or FFI)
    participant Global as Global / Hub
    participant Device
    participant Tracker as track/*
    participant Hal as wgpu-hal
    User->>Global: queue_submit(queue_id, command_buffers)
    Global->>Device: queue.submit(...)
    Device->>Tracker: merge command-buffer trackers
    Tracker->>Tracker: compute usage transitions
    Device->>Hal: encode barriers via cmd_buf
    Device->>Hal: queue.submit(cmd_bufs, fence)
    Hal-->>Device: submission index
    Device->>Device: register resources with LifetimeTracker

The flow above is the most important one to understand. Every command-buffer recording produces per-buffer-buffer trackers; submission merges them into the device's tracker, computes the necessary barriers, encodes them, and submits the resulting hal-level command buffers. LifetimeTracker then records that the resources used by the submission can be dropped once the GPU finishes.

Validation

Validation is woven through the implementation rather than living in a separate "validator" module. Each method on Global (in wgpu-core/src/device/global.rs) calls into Device::create_buffer, Device::create_render_pipeline, etc. (in device/resource.rs), which performs descriptor checks before constructing the underlying HAL resource.

Cross-cutting validators that do live in named modules:

  • Shader binding validation (wgpu-core/src/validation.rs, ~85 KB) — checks that a pipeline's bind group layouts match its shader's interface.
  • Limit checking (wgpu-core/src/limits.rs) — sanity-checks Limits against the adapter's capabilities.
  • Indirect-draw validation (wgpu-core/src/indirect_validation/) — a compute shader runs at submission time to validate multi_draw_indirect_* parameters before the GPU consumes them. This is the only place where wgpu-core itself runs a GPU pipeline.
  • Init tracker (wgpu-core/src/init_tracker/) — clears uninitialized buffer/texture regions on first use to avoid leaking previous contents.
  • Timestamp normalization (wgpu-core/src/timestamp_normalization/) — another compute shader that maps HAL timestamp counters into nanoseconds, smoothing over driver differences.

Locking

wgpu-core uses fine-grained, ranked locks (wgpu-core/src/lock/). Every Mutex/RwLock is created with a static rank; the lock helpers panic in debug builds if locks are taken out of order. Recent commits show this is actively maintained:

  • fix(core): Order BUFFER_MAP_STATE lock after QUEUE_PENDING_WRITES
  • fix(core): Don't overlap QUEUE_PENDING_WRITES and QUEUE_LIFE_TRACKER locks

When you add a new lock, pick or add a rank in wgpu-core/src/lock/rank.rs. Run cargo nextest run -p wgpu-core — the lock helpers will surface ordering violations.

Public API surface

wgpu-core is consumed in two ways:

  1. Through the wgpu crate — every method on Global is wrapped by wgpu/src/backend/wgpu_core.rs.
  2. Directly, via Firefox / Deno — Firefox's gfx/wgpu_bindings/ and Deno's deno_webgpu/ (in this repo!) call Global::queue_submit, Global::device_create_buffer, etc. The shape of every method makes the parameters trivially convertible across an FFI boundary: take an Id, return a Result<Id, Error> or Result<(), Error>.

This is why wgpu-core is extern crate wgpu_hal as hal; extern crate wgpu_types as wgt; and not use wgpu_hal::*; — the layout of its public types must be predictable.

Integration points

  • Above: wgpu (wgpu/src/backend/wgpu_core.rs), deno_webgpu (deno_webgpu/), Firefox's wgpu_bindings.
  • Below: wgpu-hal for everything that touches the GPU; wgpu-naga-bridge for shader translation; wgpu-types for plain data.
  • Optional: enables Trace recording (wgpu-core/src/device/trace.rs) consumed by player.

Entry points for modification

  • A new WebGPU method — add a method to Global in wgpu-core/src/device/global.rs, calling into the matching Device method in device/resource.rs. Validate the descriptor; obtain the HAL handle; allocate an Id; insert into the registry; return the Id.
  • A new validation rule — add the check inside the relevant Device::create_X method, returning a typed error from the module's error enum. Add a test in tests/tests/wgpu-validation/ so it's covered without a real GPU.
  • A new state-tracking case — modify the appropriate track/* module. The trackers operate on Ids and produce HAL-level transitions.
  • A new lock — see patterns-and-conventions. Always use wgpu-core/src/lock/'s helpers, never raw parking_lot.

For deep dives on individual subsystems (the tracker, the lifetime manager, the trace format), wgpu-core/src/track/, wgpu-core/src/device/life.rs, and wgpu-core/src/device/trace.rs are the canonical reads.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

wgpu-core – wgpu wiki | Factory