Metal Core Image Filter does not Compile

In an application, I am using a Metal filter to remove the background from a playing video. Here is the filter's complete code:
Code Block Metal
#include <metal_stdlib>
#include <CoreImage/CoreImage.h> // includes CIKernelMetalLib.h
extern "C" {
    namespace coreimage {
        float4 alphaFrame(sampler source, sampler mask) {
            float4 color = source.sample(source.coord());
            float opacity = mask.sample(mask.coord()).r;
            return float4(color.rgb, opacity);
        }
    }
}

The problem is that, when compiling in Xcode 12 for iOS 14, two errors pop up about this file preventing the build from compiling: "/air-lld:1:1: symbol(s) not found for target 'air64-apple-ios13.0.0'" and "air-lld command failed with exit code 1 (use -v to see invocation)". If I comment out the filter, the build is able to compile as normal. How can I use this filter in my app and have it compile as well?

Answered by Graphics and Games Engineer in 616138022
Thank you for the detailed question.

It looks like your build does not use the required -fcikernel compile option and -cikernel link option. You can set up the project to include those with the instructions provided in WWDC20 session, "Build Metal-based Core Image kernels with Xcode". For its first custom build rule, please use -I MTL_HEADER_SEARCH_PATHS only if your build setting for MTL_HEADER_SEARCH_PATHS is non-empty.

Also note that, despite use of namespace, all functions marked extern "C" link as if in a common namespace. You would not be able to have any other extern "C" function with same name, "alphaFrame". Your particular syntax puts your function in a system namespace, which may result in other name collisions, as the project grows.

The following version, without namespace, compiles correctly using the directions from the session, sans -I:

Code Block
#include <metal_stdlib>
#include <CoreImage/CoreImage.h> // includes CIKernelMetalLib.h
extern "C" {
float4 alphaFrame(coreimage::sampler source, coreimage::sampler mask) {
float4 color = source.sample(source.coord());
float opacity = mask.sample(mask.coord()).r;
return float4(color.rgb, opacity);
}
}

Thank you for the detailed question.

It looks like your build does not use the required -fcikernel compile option and -cikernel link option. You can set up the project to include those with the instructions provided in WWDC20 session, "Build Metal-based Core Image kernels with Xcode". For its first custom build rule, please use -I MTL_HEADER_SEARCH_PATHS only if your build setting for MTL_HEADER_SEARCH_PATHS is non-empty.

Also note that, despite use of namespace, all functions marked extern "C" link as if in a common namespace. You would not be able to have any other extern "C" function with same name, "alphaFrame". Your particular syntax puts your function in a system namespace, which may result in other name collisions, as the project grows.

The following version, without namespace, compiles correctly using the directions from the session, sans -I:

Code Block
#include <metal_stdlib>
#include <CoreImage/CoreImage.h> // includes CIKernelMetalLib.h
extern "C" {
float4 alphaFrame(coreimage::sampler source, coreimage::sampler mask) {
float4 color = source.sample(source.coord());
float opacity = mask.sample(mask.coord()).r;
return float4(color.rgb, opacity);
}
}

It's also worth noting that there is a built-in filter that does exactly that: CIBlendWithRedMask

Uses values from a mask image to interpolate between an image and the background. When a mask red value is 0.0, the result is the background. When the mask red value is 1.0, the result is the image.


Metal Core Image Filter does not Compile
 
 
Q