ADR-0437: Metal public-header install and vmaf_metal_import_state declaration¶
- Status: Accepted
- Date: 2026-05-15
- Deciders: lusoris, Claude (Anthropic)
- Tags: metal, build, c-api, install, apple-silicon, fork-local
Context¶
Audit slice B (2026-05-15) identified two gaps that block downstream FFmpeg --enable-libvmaf-metal integration:
-
Install gap:
libvmaf_metal.hwas absent from theplatform_specific_headerslist incore/include/core/meson.build. Every other backend header (libvmaf_cuda.h,libvmaf_sycl.h,libvmaf_vulkan.h,libvmaf_hip.h,libvmaf_mcp.h,dnn.h) has a conditionalinstall_headersentry; Metal did not. Ameson install -Denable_metal=enabledbuild therefore left the Metal header out of the installed tree, causing the FFmpeg configure probecheck_pkg_config libvmaf_metal ... libvmaf/libvmaf_metal.h vmaf_metal_state_initto silently fail — the same class of failure that triggered ADR-0192's Vulkan guard. -
Declaration gap:
vmaf_metal_import_state(the entry point that hands aVmafMetalStateto aVmafContext, mirroringvmaf_cuda_import_state/vmaf_vulkan_import_state/vmaf_sycl_import_state) was implemented incore/src/libvmaf.c:648but the public declaration was missing fromcore/include/libvmaf/libvmaf_metal.h. Without it callers could not bind aVmafContextto the Metal backend even if the header were installed. (Subsequent review confirmed the declaration was added to the header in an earlier PR before this ADR was written; the install gap was the surviving blocker.)
Both gaps were introduced in the original Metal scaffold (ADR-0361 / T8-1) and survived the runtime (ADR-0420), kernel (ADR-0421), and IOSurface import (ADR-0423) follow-ups because the install list was never updated.
The same pattern was previously fixed for Vulkan in ADR-0192, which introduced the is_vulkan_enabled guard that treats both enabled and auto as "install the header". This ADR applies the identical logic to Metal's feature option.
Decision¶
We will:
- Add a
is_metal_enabledboolean incore/include/core/meson.buildthat resolves totruewhenenable_metalisenabledorauto, and conditionally appendlibvmaf_metal.htoplatform_specific_headers. - Verify
vmaf_metal_import_stateis correctly declared inlibvmaf_metal.hwith the signatureint vmaf_metal_import_state(VmafContext *ctx, VmafMetalState *state). - Fix
docs/api/gpu.md— replace the three wrong symbol names (vmaf_metal_state_new→vmaf_metal_state_init,vmaf_metal_import_iosurface→vmaf_metal_picture_import,vmaf_hip_state_new→vmaf_hip_state_init) and add the missing IOSurface sub-API table (VmafMetalExternalHandles,vmaf_metal_state_init_external,vmaf_metal_picture_import,vmaf_metal_wait_compute,vmaf_metal_read_imported_pictures). - Add a macOS-only compile+link smoke test
core/test/test_metal_install_header.cthat takes function-pointer addresses for every public Metal symbol — a type mismatch is a compile error, so the test catches ABI drift between header and library.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Leave Metal out of install list | No change required | Breaks FFmpeg --enable-libvmaf-metal configure probes; contradicts ADR-0420 "live runtime" posture | Rejected — violates ADR-0100 per-surface documentation + install contract |
Wrap vmaf_metal_import_state declaration behind #ifdef VMAF_INTERNAL | Keeps public header minimal | Public callers cannot bind a VmafContext to Metal; defeats the entire API | Rejected — the function is part of the public lifecycle contract |
Treat enable_metal=auto as "do not install on non-macOS" | Avoids header install on Linux where Metal is always absent | Inconsistent with Vulkan/DNN auto treatment; pkg-config on cross-compile hosts needs the header present | Rejected — install the header whenever the option is not disabled, mirroring the Vulkan guard |
Consequences¶
- Positive: FFmpeg
--enable-libvmaf-metalconfigure probes can now findlibvmaf_metal.hin the install tree. Callers can bind aVmafContextto the Metal backend viavmaf_metal_import_state. Thedocs/api/gpu.mdMetal section accurately reflects the live API. - Negative: Adds one more installed header on macOS (negligible footprint).
- Neutral / follow-ups: The
test_metal_install_headersmoke test runs on every macOS CI build and will catch any future ABI drift between the public declaration and the library symbol.
References¶
- Audit slice B finding §B.7 #1 (install gap) and §B.4 #2+#4 (declaration + docs gaps):
.workingdir/audit-2026-05-15/B-c-api-and-build.md. - ADR-0192 (Vulkan header install guard — precedent for feature-option install logic).
- ADR-0361 (Metal scaffold), ADR-0420 (Metal runtime), ADR-0423 (IOSurface import).
- Gap-fill plan Batch 4:
.workingdir/GAP-FILL-PLAN-2026-05-15.md.