Skip to content

Commit

Permalink
lavfi/metal: fix build with pre-10.11 deployment targets
Browse files Browse the repository at this point in the history
- Ensure the yadif .metal compiles when targeting any Metal runtime version
- Use some preprocessor awkwardness to ensure Core Video's Metal-specific
  functionality is exposed regardless of our deployment target (this works
  around what seems to be an SDK header bug, filed as FB9816002)
- Ensure all direct references to Metal functions and classes are gated
  behind runtime version checks (this satisfies clang's deployment-target
  violation warnings provided by -Wunguarded-availability).
  • Loading branch information
rcombs committed Dec 23, 2021
1 parent 0f77ee9 commit 8e24a8e
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 12 deletions.
28 changes: 26 additions & 2 deletions libavfilter/metal/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,40 @@
#define AVFILTER_METAL_UTILS_H

#include <Metal/Metal.h>

#include <AvailabilityMacros.h>

// CoreVideo accidentally(?) preprocessor-gates Metal functionality
// on MAC_OS_X_VERSION_MIN_REQUIRED >= 101100 (FB9816002).
// There doesn't seem to be any particular reason for this,
// so here we temporarily redefine it to at least that value
// so CV will give us CVMetalTextureRef and the related functions.

#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101100)
#define ORIG_MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_MIN_REQUIRED
#undef MAC_OS_X_VERSION_MIN_REQUIRED
#define MAC_OS_X_VERSION_MIN_REQUIRED 101100
#endif

#include <CoreVideo/CoreVideo.h>

#ifdef ORIG_MAC_OS_X_VERSION_MIN_REQUIRED
#undef MAC_OS_X_VERSION_MIN_REQUIRED
#define MAC_OS_X_VERSION_MIN_REQUIRED ORIG_MAC_OS_X_VERSION_MIN_REQUIRED
#undef ORIG_MAC_OS_X_VERSION_MIN_REQUIRED
#endif

void ff_metal_compute_encoder_dispatch(id<MTLDevice> device,
id<MTLComputePipelineState> pipeline,
id<MTLComputeCommandEncoder> encoder,
NSUInteger width, NSUInteger height);
NSUInteger width, NSUInteger height)
API_AVAILABLE(macos(10.11), ios(8.0));

CVMetalTextureRef ff_metal_texture_from_pixbuf(void *avclass,
CVMetalTextureCacheRef textureCache,
CVPixelBufferRef pixbuf,
int plane,
MTLPixelFormat format);
MTLPixelFormat format)
API_AVAILABLE(macos(10.11), ios(8.0));

#endif /* AVFILTER_METAL_UTILS_H */
11 changes: 10 additions & 1 deletion libavfilter/metal/vf_yadif_videotoolbox.metal
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@

using namespace metal;

/*
* Version compat shims
*/

#if __METAL_VERSION__ < 210
#define max3(x, y, z) max(x, max(y, z))
#define min3(x, y, z) min(x, min(y, z))
#endif

/*
* Parameters
*/
Expand All @@ -44,7 +53,7 @@ struct deintParams {
*/

#define accesstype access::sample
const sampler s(coord::pixel);
constexpr sampler s(coord::pixel);

template <typename T>
T tex2D(texture2d<float, access::sample> tex, uint x, uint y)
Expand Down
67 changes: 58 additions & 9 deletions libavfilter/vf_yadif_videotoolbox.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
#include "libavutil/hwcontext.h"
#include "libavutil/objc.h"

#include <assert.h>

extern char ff_vf_yadif_videotoolbox_metallib_data[];
extern unsigned int ff_vf_yadif_videotoolbox_metallib_len;

typedef struct YADIFVTContext {
typedef struct API_AVAILABLE(macos(10.11), ios(8.0)) YADIFVTContext {
YADIFContext yadif;

AVBufferRef *device_ref;
Expand All @@ -44,7 +46,12 @@
id<MTLBuffer> mtlParamsBuffer;

CVMetalTextureCacheRef textureCache;
} YADIFVTContext;
} YADIFVTContext API_AVAILABLE(macos(10.11), ios(8.0));

// Using sizeof(YADIFVTContext) outside of an availability check will error
// if we're targeting an older OS version, so we need to calculate the size ourselves
// (we'll statically verify it's correct in yadif_videotoolbox_init behind a check)
#define YADIF_VT_CTX_SIZE (sizeof(YADIFContext) + sizeof(void*) * 10)

struct mtlYadifParams {
uint channels;
Expand All @@ -62,7 +69,7 @@ static void call_kernel(AVFilterContext *ctx,
id<MTLTexture> next,
int channels,
int parity,
int tff)
int tff) API_AVAILABLE(macos(10.11), ios(8.0))
{
YADIFVTContext *s = ctx->priv;
id<MTLCommandBuffer> buffer = s->mtlQueue.commandBuffer;
Expand Down Expand Up @@ -93,7 +100,7 @@ static void call_kernel(AVFilterContext *ctx,
}

static void filter(AVFilterContext *ctx, AVFrame *dst,
int parity, int tff)
int parity, int tff) API_AVAILABLE(macos(10.11), ios(8.0))
{
YADIFVTContext *s = ctx->priv;
YADIFContext *y = &s->yadif;
Expand Down Expand Up @@ -162,7 +169,7 @@ static void filter(AVFilterContext *ctx, AVFrame *dst,
return;
}

static av_cold void yadif_videotoolbox_uninit(AVFilterContext *ctx)
static av_cold void do_uninit(AVFilterContext *ctx) API_AVAILABLE(macos(10.11), ios(8.0))
{
YADIFVTContext *s = ctx->priv;
YADIFContext *y = &s->yadif;
Expand All @@ -188,7 +195,15 @@ static av_cold void yadif_videotoolbox_uninit(AVFilterContext *ctx)
}
}

static av_cold int yadif_videotoolbox_init(AVFilterContext *ctx)

static av_cold void yadif_videotoolbox_uninit(AVFilterContext *ctx)
{
if (@available(macOS 10.11, iOS 8.0, *)) {
do_uninit(ctx);
}
}

static av_cold int do_init(AVFilterContext *ctx) API_AVAILABLE(macos(10.11), ios(8.0))
{
YADIFVTContext *s = ctx->priv;
NSError *err = nil;
Expand Down Expand Up @@ -261,7 +276,19 @@ static av_cold int yadif_videotoolbox_init(AVFilterContext *ctx)
return AVERROR_EXTERNAL;
}

static int config_input(AVFilterLink *inlink)
static av_cold int yadif_videotoolbox_init(AVFilterContext *ctx)
{
if (@available(macOS 10.11, iOS 8.0, *)) {
// Ensure we calculated YADIF_VT_CTX_SIZE correctly
static_assert(YADIF_VT_CTX_SIZE == sizeof(YADIFVTContext), "Incorrect YADIF_VT_CTX_SIZE value!");
return do_init(ctx);
} else {
av_log(ctx, AV_LOG_ERROR, "Metal is not available on this OS version\n");
return AVERROR(ENOSYS);
}
}

static int do_config_input(AVFilterLink *inlink) API_AVAILABLE(macos(10.11), ios(8.0))
{
AVFilterContext *ctx = inlink->dst;
YADIFVTContext *s = ctx->priv;
Expand All @@ -283,7 +310,18 @@ static int config_input(AVFilterLink *inlink)
return 0;
}

static int config_output(AVFilterLink *link)
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
if (@available(macOS 10.11, iOS 8.0, *)) {
return do_config_input(inlink);
} else {
av_log(ctx, AV_LOG_ERROR, "Metal is not available on this OS version\n");
return AVERROR(ENOSYS);
}
}

static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios(8.0))
{
AVHWFramesContext *output_frames;
AVFilterContext *ctx = link->src;
Expand Down Expand Up @@ -347,6 +385,17 @@ static int config_output(AVFilterLink *link)
return ret;
}

static int config_output(AVFilterLink *link)
{
AVFilterContext *ctx = link->src;
if (@available(macOS 10.11, iOS 8.0, *)) {
return do_config_output(link);
} else {
av_log(ctx, AV_LOG_ERROR, "Metal is not available on this OS version\n");
return AVERROR(ENOSYS);
}
}

#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }

Expand Down Expand Up @@ -394,7 +443,7 @@ static int config_output(AVFilterLink *link)
AVFilter ff_vf_yadif_videotoolbox = {
.name = "yadif_videotoolbox",
.description = NULL_IF_CONFIG_SMALL("YADIF for VideoToolbox frames using Metal compute"),
.priv_size = sizeof(YADIFVTContext),
.priv_size = YADIF_VT_CTX_SIZE,
.priv_class = &yadif_videotoolbox_class,
.init = yadif_videotoolbox_init,
.uninit = yadif_videotoolbox_uninit,
Expand Down

0 comments on commit 8e24a8e

Please sign in to comment.