Over a million developers have joined DZone.

Metal Kernel Functions as Core Image Filter Engines

Using Metal compute functions is way more efficient but requires boilerplate code. Simon Gladman helps you avoid this with his MetalFilter.

· Mobile Zone

Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud, brought to you in partnership with IBM.

Whoa! A CoreImage filter for generating Perlin Noise based on a Metal compute function.

The chapter in my book, Core Image for Swift, that discusses creating custom filters and writing GLSL has become one of the largest and the most enjoyable to write. I've written a handful of new filters which I posted about recently. However, writing Core Image kernels is a bit of a pain since the GLSL code is passed to CIKernel as strings and the tooling is a tad lacking. Here's the carefully constructed super simple threshold code:

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
            super.init(functionName: "kuwahara")

        required init?(coder aDecoder: NSCoder)
            fatalError("init(coder:) has not been implemented")

        var inputRadius: CGFloat = 15

        override func setDefaults()
            inputRadius = 15

        override var 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 pre-order 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.

The Mobile Zone is brought to you in partnership with Strongloop and IBM.  Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud.


Published at DZone with permission of Simon Gladman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}