Open-Source Wikis

/

wgpu

/

Crates

/

Metal backend

gfx-rs/wgpu

Metal backend

Active contributors: Andy Leiserson, teoxoy, Connor Fitzgerald

The Metal backend (wgpu-hal/src/metal/) targets macOS, iOS, and tvOS. It uses the objc2 family of crates to call Apple's Metal framework directly — there is no third-party metal crate in the dependency tree.

Directory layout

wgpu-hal/src/metal/
├── mod.rs               ~36 KB — Api impl, types, lifecycle
├── adapter.rs           ~78 KB — feature detection, limits, format support
├── command.rs           ~77 KB — CommandEncoder
├── conv.rs              ~19 KB — type conversions
├── device.rs            ~91 KB — resource creation
├── library_from_metallib.rs  load precompiled .metallib shader libraries
├── surface.rs           ~7 KB — CAMetalLayer integration
└── time.rs              timer helpers

The 91 KB device.rs and 77 KB command.rs together implement most of the backend; adapter.rs is unusually large because Metal feature support is fragmented across iOS/macOS major versions, GPU families, and OS minor versions.

Key abstractions

Type File Purpose
metal::Api wgpu-hal/src/metal/mod.rs The HAL Api impl.
metal::Instance, Adapter, Device, Queue wgpu-hal/src/metal/{adapter,mod}.rs Lifecycle types.
metal::CommandEncoder wgpu-hal/src/metal/command.rs Wraps MTLCommandBuffer and the per-pass encoder objects.
metal::Buffer, Texture, Sampler, BindGroup, ... wgpu-hal/src/metal/mod.rs Resource structs holding Retained<MTLBuffer> etc.
metal::Surface wgpu-hal/src/metal/surface.rs Wraps CAMetalLayer.

How it works

Metal's render encoder model is closer to WebGPU than Vulkan's render-pass model is, so much of command.rs is straightforward translation:

graph LR
    Core[wgpu-core] -->|begin_render_pass| Enc[metal::CommandEncoder]
    Enc -->|MTLRenderPassDescriptor| Cmd[MTLCommandBuffer]
    Cmd -->|render encoder| RenderEnc[MTLRenderCommandEncoder]
    RenderEnc -->|setRenderPipelineState, draw, ...| GPU
    Core -->|queue.submit| Queue[metal::Queue]
    Queue -->|presentDrawable + commit| GPU
    Queue -->|MTLEvent / MTLSharedEvent for fences| GPU

Notable features and recent work

  • Autorelease pool discipline — recent commits added missing autorelease pools in several places (fix(metal): Add missing autorelease pools). On Apple platforms each thread that uses Objective-C objects needs an active autorelease pool or peak memory grows unboundedly.
  • arm64_32 / watchOS — PR #9411 added arm64_32 (ILP32, watchOS) target support.
  • Shader barycentric introspection — PR #9472 fixes a barycentric-coordinate detection bug by using ObjC introspection of supportsShaderBarycentricCoordinates instead of a feature-set check.
  • Acceleration structures — Metal's ray-tracing types (MTLAccelerationStructure*) are wired through adapter.rs and device.rs. Compatible with the EXPERIMENTAL_RAY_TRACING_* feature bits.
  • Argument buffers — Metal's argument-buffer model is used to back wgpu's bind groups. The translation from BindGroupLayout → argument buffer encoder lives in device.rs.

Shader integration

Metal needs MSL source. wgpu-naga-bridge invokes naga::back::msl to translate WGSL → MSL just before the shader module is created. The MSL is then handed to MTLDevice::newLibraryWithSource:, and the resulting MTLLibrary/MTLFunctions drive pipeline construction. library_from_metallib.rs is the alternate path: precompiled .metallib blobs supplied by the user, useful for faster startup.

Validation

InstanceFlags::DEBUG enables a few diagnostics (MTLCommandBuffer::setLabel). For real validation, set MTL_DEBUG_LAYER=1 in the environment, which Apple's runtime honors. The shared validation_canary is not hooked into Metal — Metal's validation layer doesn't expose a programmatic callback. Capturing in Xcode's GPU Frame Debugger remains the most useful debugging path.

Memory allocation

Metal's resource allocators are unified, and MTLDevice exposes coarser controls than Vulkan/DX12. wgpu-hal/src/metal/device.rs uses newBufferWithLength:options: and newTextureWithDescriptor: directly; there is no analogue to gpu-allocator. MTLResidencySet (Apple Silicon only) is wired up to keep the working set explicit.

Integration points

  • Above: wgpu-core.
  • Below: objc2, objc2-foundation, objc2-metal, objc2-core-foundation, objc2-quartz-core, block2, raw-window-metal (for CAMetalLayer from raw-window-handle).
  • Sideways: shares no backend-specific helpers with the others except via wgpu-hal/src/auxil/.

Entry points for modification

  • A new feature — start in wgpu-hal/src/metal/adapter.rs::Adapter::detect_features. Each Features bit is gated by a check on Metal's MTLDevice.supportsFamily:, OS major version, or capability flag. Plumb the implementation through device.rs and command.rs.
  • A new descriptor or command — translate it in command.rs. Watch for autorelease pool placement on hot paths.
  • A workaround — Metal regressions and known issues are tracked in inline comments throughout device.rs and adapter.rs. There's no central "quirks" table; the convention is to attach a comment with the OS version and a radar URL near the affected code.

For the WGSL → MSL translation itself, see crates/naga/backends.

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

Metal backend – wgpu wiki | Factory