Skip to content

Add swift_sources sibling: metal_sources for watchOS/iOS/tvOS Metal shader compilation #124

@proggeramlug

Description

@proggeramlug

Summary

Perry's `perry.nativeLibrary.targets..swift_sources` manifest field (added in #118) lets a native lib ship Swift files that Perry compiles + links alongside its Rust staticlib. A parallel `metal_sources` field would let a native lib ship Metal shader files that Perry compiles to a `.metallib` and bundles into the `.app`, so SwiftUI on watchOS 10+ / iOS 17+ can use them via `.colorEffect(Shader(function: .init(library: .default, name: "..."), ...))`.

Why

Bloom's cross-platform post-fx surface includes chromatic aberration, film grain, and sun shafts — all of which need per-pixel shaders. On wgpu platforms (macOS / tvOS / iOS game-loop / Windows / Linux) bloom runs its own WGSL pipeline. On watchOS (`watchos-swift-app` path), SwiftUI can host them via `.colorEffect(shader:)` / `.layerEffect(shader:)` / `.visualEffect(_:)` — but only if a compiled Metal library is present in the bundle as `default.metallib`.

Today there's no way to ship a `.metal` file with a native lib through Perry. The bloom-side tracking issue (`Bloom-Engine/engine#16`) is blocked on this.

Proposed design

New optional manifest field:

```json
"watchos": {
"crate": "native/watchos/",
"lib": "libbloom_watchos.a",
"frameworks": ["WatchKit", "SwiftUI", "SceneKit", ...],
"swift_sources": ["native/watchos/src/BloomWatchApp.swift"],
"metal_sources": ["native/watchos/shaders/chromatic_aberration.metal",
"native/watchos/shaders/film_grain.metal",
"native/watchos/shaders/sun_shafts.metal"]
}
```

Perry, when `metal_sources` is non-empty:

  1. For each `.metal`, run `xcrun -sdk metal -c -target -o .air .metal`.
  2. Run `xcrun -sdk metallib -o default.metallib <all .air files>`.
  3. Copy `default.metallib` into the `.app` root (alongside `Info.plist`) — that's the path SwiftUI's `ShaderLibrary.default` loads from.

Triple for the metal compile matches the existing watchos-sim / watchos mapping Perry already uses for swiftc. Same pattern on iOS / tvOS if we want those to benefit — scope to watchos for v1 if simpler.

Scope note

No wiring into the Rust side needed — `.metallib` is consumed at runtime by SwiftUI / Metal's dynamic loader, not by the linker. The file just needs to land in the `.app` at the right path.

Acceptance

`perry compile --target watchos-simulator --features watchos-swift-app src/main.ts` with a bloom package that declares three `metal_sources` produces `BloomJumpWatch.app/default.metallib` containing all three shader functions, and `Shader(function: .init(library: .default, name: "chromatic_aberration"), ...)` resolves at runtime.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions