Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions changelog.d/fixed/hip-metal-enosys-stubs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# fix(core): emit -ENOSYS stubs for libvmaf_hip.h / libvmaf_metal.h when backend is OFF

Both `core/include/libvmaf/libvmaf_hip.h` and
`core/include/libvmaf/libvmaf_metal.h` document the contract that every
public entry point returns `-ENOSYS` when libvmaf is built without the
relevant backend. The real bodies in `core/src/hip/common.c`,
`core/src/metal/common.mm`, `core/src/metal/picture_import.mm`, and the
`vmaf_hip_import_state` / `vmaf_metal_import_state` /
`vmaf_metal_read_imported_pictures` definitions inside `core/src/libvmaf.c`
all sit behind `#ifdef HAVE_HIP` / `#ifdef HAVE_METAL`, so a default
`-Denable_hip=false -Denable_metal=disabled` build emitted none of those
symbols into `libvmaf.so` and any downstream link that referenced them
failed.

Fix: add `core/src/hip/stubs.c` + `core/src/metal/stubs.c` that mirror the
canonical `core/src/dnn/dnn_api.c` `VMAF_HAVE_DNN` stub pattern and wire
each TU into `libvmaf_feature_static_lib` via `hip_sources` /
`metal_sources` only when the backend is disabled. The stubs return
`-ENOSYS`, set out-params to NULL on the pointer-returning entry points,
and `vmaf_hip_available()` / `vmaf_metal_available()` correctly return 0.
6 changes: 6 additions & 0 deletions core/src/hip/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ hip/
picture_hip.{c,h} # VmafPicture on a HIP device — stub
dispatch_strategy.{c,h} # Feature-name → kernel routing — stub
kernel_template.{h,c} # per-feature HIP kernel scaffolding (T7-10 / ADR-0241)
stubs.c # -ENOSYS fallbacks for the public libvmaf_hip.h
# entry points when HAVE_HIP is OFF. Wired in
# from core/src/meson.build's `else` branch of
# `if is_hip_enabled`, NOT via `subdir('hip')`.
# Mirrors core/src/dnn/dnn_api.c's VMAF_HAVE_DNN
# stub pattern.
meson.build # subdir() include from libvmaf/src/meson.build
```

Expand Down
72 changes: 72 additions & 0 deletions core/src/hip/stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright 2026 Lusoris and Claude (Anthropic)
* SPDX-License-Identifier: BSD-3-Clause-Plus-Patent
*
* Licensed under the BSD+Patent License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSDplusPatent
*
* -ENOSYS fallbacks for the public `libvmaf/libvmaf_hip.h` surface
* when libvmaf is built without `-Denable_hip=true`. Mirrors the
* `core/src/dnn/dnn_api.c` pattern that already does the same for
* `VMAF_HAVE_DNN`.
*
* Without these stubs the entries declared in libvmaf_hip.h are not
* emitted into libvmaf.so at all (the real implementations live in
* `hip/common.c` + `libvmaf.c` under `#ifdef HAVE_HIP`), so any
* downstream consumer that links against libvmaf and references the
* HIP entry points fails at link time. The header documents the
* contract — "every entry point returns -ENOSYS unconditionally" —
* and these stubs honour it.
*
* Meson wires this TU into `libvmaf_sources` only when
* `is_hip_enabled == false`. When HIP is enabled the real
* implementations in `hip/common.c` and `libvmaf.c` take over.
*/

#include "config.h"

#ifndef HAVE_HIP

#include <errno.h>
#include <stddef.h>

#include "libvmaf/libvmaf.h"
#include "libvmaf/libvmaf_hip.h"

int vmaf_hip_available(void)
{
return 0;
}

int vmaf_hip_state_init(VmafHipState **out, VmafHipConfiguration cfg)
{
(void)cfg;
if (out != NULL) {
*out = NULL;
}
return -ENOSYS;
}

int vmaf_hip_import_state(VmafContext *ctx, VmafHipState *state)
{
(void)ctx;
(void)state;
return -ENOSYS;
}

void vmaf_hip_state_free(VmafHipState **state)
{
if (state != NULL) {
*state = NULL;
}
}

int vmaf_hip_list_devices(void)
{
return -ENOSYS;
}

#endif /* !HAVE_HIP */
17 changes: 17 additions & 0 deletions core/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ endif
if is_hip_enabled
cdata.set10('HAVE_HIP', true)
subdir('hip')
else
# ADR-0212 / libvmaf_hip.h contract: every public HIP entry point
# returns -ENOSYS when libvmaf is built without HIP support. Without
# this stub TU the symbols are not emitted into libvmaf.so at all
# (the real bodies in hip/common.c + libvmaf.c sit behind
# `#ifdef HAVE_HIP`) and downstream consumers fail at link time.
# Mirrors the `core/src/dnn/dnn_api.c` `VMAF_HAVE_DNN` stub pattern.
hip_sources += files('hip/stubs.c')
endif

# HIP HSACO device-kernel pipeline (ADR-0372 / T7-10b batch-1).
Expand Down Expand Up @@ -334,6 +342,15 @@ metal_deps = []
if is_metal_enabled
cdata.set10('HAVE_METAL', true)
subdir('metal')
else
# ADR-0361 / libvmaf_metal.h contract: every public Metal entry point
# returns -ENOSYS when libvmaf is built without Metal support (or the
# auto-probe failed on a non-macOS host). Without this stub TU the
# symbols are not emitted into libvmaf.so at all (the real bodies in
# metal/common.mm + metal/picture_import.mm + libvmaf.c sit behind
# `#ifdef HAVE_METAL`) and downstream consumers fail at link time.
# Mirrors the `core/src/dnn/dnn_api.c` `VMAF_HAVE_DNN` stub pattern.
metal_sources += files('metal/stubs.c')
endif
if dnn_have_ort
cdata.set10('HAVE_DNN', true)
Expand Down
6 changes: 6 additions & 0 deletions core/src/metal/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ metal/
picture_metal.{mm,h} # VmafPicture on a Metal device — MTLBuffer lifecycle (T8-1b)
dispatch_strategy.{c,h} # Feature-name → landed-kernel support predicate
kernel_template.{mm,h} # per-feature kernel scaffolding + runtime (T8-1b / ADR-0420)
stubs.c # -ENOSYS fallbacks for the public libvmaf_metal.h
# entry points when HAVE_METAL is OFF. Wired in
# from core/src/meson.build's `else` branch of
# `if is_metal_enabled`, NOT via `subdir('metal')`.
# Mirrors core/src/dnn/dnn_api.c's VMAF_HAVE_DNN
# stub pattern.
meson.build # subdir() include from libvmaf/src/meson.build
```

Expand Down
109 changes: 109 additions & 0 deletions core/src/metal/stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright 2026 Lusoris and Claude (Anthropic)
* SPDX-License-Identifier: BSD-3-Clause-Plus-Patent
*
* Licensed under the BSD+Patent License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSDplusPatent
*
* -ENOSYS fallbacks for the public `libvmaf/libvmaf_metal.h` surface
* when libvmaf is built without `-Denable_metal=enabled` (or the
* auto-probe failed on a non-macOS host). Mirrors the
* `core/src/dnn/dnn_api.c` pattern that already does the same for
* `VMAF_HAVE_DNN` and the sibling `core/src/hip/stubs.c` for HIP.
*
* Without these stubs the entries declared in libvmaf_metal.h are
* not emitted into libvmaf.so at all (the real implementations live
* in `metal/common.mm` + `metal/picture_import.mm` + `libvmaf.c`
* under `#ifdef HAVE_METAL`), so any downstream consumer that links
* against libvmaf and references the Metal entry points fails at
* link time. The header documents the contract — "every entry point
* returns -ENOSYS unconditionally" — and these stubs honour it.
*
* Meson wires this TU into `libvmaf_sources` only when
* `is_metal_enabled == false`. When Metal is enabled the real
* implementations take over.
*/

#include "config.h"

#ifndef HAVE_METAL

#include <errno.h>
#include <stddef.h>

#include "libvmaf/libvmaf.h"
#include "libvmaf/libvmaf_metal.h"

int vmaf_metal_available(void)
{
return 0;
}

int vmaf_metal_state_init(VmafMetalState **out, VmafMetalConfiguration cfg)
{
(void)cfg;
if (out != NULL) {
*out = NULL;
}
return -ENOSYS;
}

int vmaf_metal_import_state(VmafContext *ctx, VmafMetalState *state)
{
(void)ctx;
(void)state;
return -ENOSYS;
}

void vmaf_metal_state_free(VmafMetalState **state)
{
if (state != NULL) {
*state = NULL;
}
}

int vmaf_metal_list_devices(void)
{
return -ENOSYS;
}

int vmaf_metal_state_init_external(VmafMetalState **out, VmafMetalExternalHandles handles)
{
(void)handles;
if (out != NULL) {
*out = NULL;
}
return -ENOSYS;
}

int vmaf_metal_picture_import(VmafMetalState *state, uintptr_t iosurface, unsigned plane,
unsigned w, unsigned h, unsigned bpc, int is_ref, unsigned index)
{
(void)state;
(void)iosurface;
(void)plane;
(void)w;
(void)h;
(void)bpc;
(void)is_ref;
(void)index;
return -ENOSYS;
}

int vmaf_metal_wait_compute(VmafMetalState *state)
{
(void)state;
return -ENOSYS;
}

int vmaf_metal_read_imported_pictures(VmafContext *ctx, unsigned index)
{
(void)ctx;
(void)index;
return -ENOSYS;
}

#endif /* !HAVE_METAL */
12 changes: 12 additions & 0 deletions docs/rebase-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -40384,3 +40384,15 @@ Fork-local files:
`core/src/libvmaf.c` (comments + assert),
`docs/adr/0795-prev-ref-thread-safety.md`,
`changelog.d/fixed/prev-ref-batch-thread-safety.md`.

## HIP/Metal -ENOSYS stubs for public API (2026-05-30)

no rebase impact: REASON — all touched code is fork-local. The two
new TUs (`core/src/hip/stubs.c`, `core/src/metal/stubs.c`) implement
the public contract documented in
`core/include/libvmaf/libvmaf_hip.h` / `libvmaf_metal.h`, both of
which are fork-added headers with no upstream counterpart. The Meson
gating change in `core/src/meson.build` is inside the
`if is_hip_enabled / else` / `if is_metal_enabled / else` blocks that
are also fork-local. Upstream Netflix/vmaf has no HIP or Metal
backend.
Loading