Whoa! A CoreImage filter for generating Perlin Noise based on a Metal compute function. |
let thresholdKernel = CIColorKernel(string:
"kernel vec4 thresholdFilter(__sample image, float threshold)" +
"{" +
" float luma = dot(image.rgb, vec3(0.2126, 0.7152, 0.0722));" +
" return (luma > threshold) ? vec4(1.0, 1.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);" +
"}"
)
No compile time checking - ugh! Eyes all mangled up with horrible quotes and string concatenation "+" signs all over the shop - ugh! That's just a simple one too!
Using Metal compute functions would be a great alternative, but implementing them requires a load of boilerplate code and we may want to chain together existing Core Image filters with custom Metal shaders.
Well, those problems are over! My MetalFilter class extends CIFilter and hides away all the Metal setup code. As a developer, all you need to do is write your Metal kernel and extend MetalFilter like so:
class MetalKuwaharaFilter: MetalFilter
{
init()
{
super.init(functionName: "kuwahara")
}
requiredinit?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
var inputRadius: CGFloat = 15
overridefunc setDefaults()
{
inputRadius = 15
}
overridevar attributes: [String : AnyObject]
{
return [
kCIAttributeFilterDisplayName: "Metal Kuwahara",
"inputImage": [kCIAttributeIdentity: 0,
kCIAttributeClass: "CIImage",
kCIAttributeDisplayName: "Image",
kCIAttributeType: kCIAttributeTypeImage],
"inputRadius": [kCIAttributeIdentity: 0,
kCIAttributeClass: "NSNumber",
kCIAttributeDefault: 15,
kCIAttributeDisplayName: "Radius",
kCIAttributeMin: 0,
kCIAttributeSliderMin: 0,
kCIAttributeSliderMax: 30,
kCIAttributeType: kCIAttributeTypeScalar],
]
}
}
After registering it, it behaves much like any other Core Image filter!
Performance seems to vary. Because of the setup overhead, the first call isn't massively faster than a GLSL based CIKernel, but after that the Metal based filter can be up to 50% faster. As a demonstration, I've created two implementations of the Kuwahara filter - one in Metal and one in GLSL and plugged them both into Filterpedia (both live under the "Custom Filters" category).
For a more detailed discussion, you'll have to wait for my book, Core Image for Swift, which should be available next month and, with fingers crossed, should be on preorder next week!
In the meantime, if you'd like to read more on writing filters using Metal, here's a little introduction I wrote last year: Image Processing with Metal.