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 helpersThe 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| GPUNotable 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
supportsShaderBarycentricCoordinatesinstead of a feature-set check. - Acceleration structures — Metal's ray-tracing types (
MTLAccelerationStructure*) are wired throughadapter.rsanddevice.rs. Compatible with theEXPERIMENTAL_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(forCAMetalLayerfromraw-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. EachFeaturesbit is gated by a check on Metal'sMTLDevice.supportsFamily:, OS major version, or capability flag. Plumb the implementation throughdevice.rsandcommand.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.rsandadapter.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.