A Swift Metal framework for GPU-accelerated image processing. Chain shader operations with a builder pattern to build computer vision pipelines that run entirely on the GPU.
Zero external dependencies. macOS 14.0+. Swift 5.9+.
A phantom-typed pipeline (v0.2.0) layers compile-time stage safety over the engine, so invalid orderings (eroding before thresholding, debayering RGBA) fail to compile instead of producing silent garbage at runtime — see Type-Safe Pipelines.
import Alloy
// Initialize the engine
guard let engine = CommonMetalEngine() else { return }
// Process raw Bayer sensor data
let result = try engine
.withRawData(width: 1024, height: 1024, bitDepth: 16)
.debayerRGGB()
.grayscale(strategy: .luminance)
.blur(radius: 3)
.execute(data: rawSensorData)
// Or start from RGBA data
let cropped = try engine
.withRGBAData(width: 512, height: 512)
.squareCrop(center: (x: 256, y: 256), sideLength: 200)
.donutMask(innerRadius: 20)
.execute(data: rgbaData)
// Access results
let texture = result.texture
let image = result.asNSImage()Additive typed frontend over
CommonMetalEngine(shipped in v0.2.0). The untyped builder above still works unchanged — and every operation now also has a typedPipelinesurface. GravityWell's real-time detection engines are built through it.
Pipeline<State> carries the semantic kind of the image (ColorImage, Binary, …) in a phantom type parameter — an uninhabited marker that exists only at compile time. Each operation is offered only in a constrained extension where the state permits it, so misordered stages are a compile error, not a runtime surprise:
let blobs = try Pipeline
.rgba(width: 512, height: 512) // Pipeline<ColorImage>
.blackAndWhite(threshold: 0.5) // Pipeline<Binary> — thresholding unlocks binary ops
.erosion(iterations: 2) // Pipeline<Binary> — offered only where State: BlackAndWhite
.connectedComponents(on: frameData, maxComponents: 20) // terminal: [ComponentCentroid]Erode before you threshold and it simply won't build:
Pipeline.rgba(width: 512, height: 512)
.erosion(iterations: 1)
// error: referencing instance method 'erosion' on 'Pipeline'
// requires that 'ColorImage' conform to 'BlackAndWhite'The state markers (ImageState, DevelopedImage, BlackAndWhite, Binary, …) are the constraint vocabulary; a new state that should be erodable just conforms to BlackAndWhite and gains erosion for free. Transitions are explicit: blackAndWhite moves color → binary; blur/noise aren't offered on a binary image at all (they'd destroy binariness — relax it first with the zero-cost asGrayscale()); branching ops like connectedComponents and sampleColors are typed terminals. For hot loops, prepared() builds the engine once and returns it, so you execute it per frame with no per-frame allocation — how GravityWell drives it at 30fps.
Compile-time rejection is guarded by scripts/check-compile-fixtures.sh (SPM can't assert compile failures in a test target). Design rationale lives in docs/pipeline-type-safety.md.
| Operation | Description |
|---|---|
| Debayer | RGGB Bayer pattern demosaicing (8-bit and 16-bit) |
| Grayscale | Luminance conversion with 8 strategies |
| Blur | Gaussian blur with configurable radius |
| Erosion | Morphological erosion (4 or 8-connectivity, 1-20 iterations) |
| Invert | Color inversion |
| Noise | Random noise injection |
| Peak Detection | Local intensity maxima detection with threshold filtering |
| Square Crop | Region extraction around a center point |
| Donut Mask | Circular mask with configurable inner/outer radii |
| HSV Position | HSV-to-position mapping for visualization |
| Color Sampling | GPU-accelerated color extraction at arbitrary positions |
| Connected Components | Blob detection with centroid calculation |
Add as a Swift Package dependency:
.package(path: "../alloy/Alloy")Then add "Alloy" to your target's dependencies.
- CommonMetalEngine -- Builder-pattern entry point that chains operations and manages execution
- MetalEngine -- Base class handling Metal device, command queue, and pipeline state caching
- ShaderOperation -- Protocol each GPU operation conforms to
- Metal shaders -- 12 compute kernels in
Sources/Alloy/Shaders/
Each operation has three parts: a parameter model (Models/), a Metal compute kernel (Shaders/), and a Swift builder extension (Extensions/).
cd Alloy
swift build
swift testPrivate repository.