Search code examples
swiftmetalcifiltercikernel

Metal: vertexFunction defined in .metal file becomes nil once setting Compiler and Linker Options for MSL cikernel


VertexFunction and FragmentFunction defined in .metal file worked nicely, but they became nil once I specified Compiler and Linker Options following Apple's doc: -fcikernel flag in the Other Metal Compiler Flags option, and -cikernel flat in MTLLINKER_FLAGS in User-Defined setting.

I need the settings above for cikernel with MSL (metal shading language). Indeed, cikernel with Core Image Kernel Language deprecated in 12.0.

How could I use both vertex/fragment Metal shader and MSL cikernel together?

let library = self.device?.makeDefaultLibrary()!
let pipeLineDescriptor = MTLRenderPipelineDescriptor()
pipeLineDescriptor.vertexFunction=library.makeFunction(name: "myVertexShader")
pipeLineDescriptor.fragmentFunction=library.makeFunction(name: "myFragmentShader")

Solution

  • I guess you have to compile your filter kernels separately instead of with your default Metal library.

    To do so, you could for instance give them another file extension, like .kernel and add a custom Build Rule like so:

    enter image description here

    Then add a custom Build Phase that copies the compiled kernel metallibs into your app bundle:

    enter image description here

    To initialize the CIKernel with the correct metal source, you can do something like this:

    let url = Bundle(for: type(of: self)).url(forResource: "<#name of your .kernel file#>", withExtension: "metallib")!
    let data = try! Data(contentsOf: url)
    let kernel = try! CIKernel(functionName: "<#kernel function name#>", fromMetalLibraryData: data)
    

    (Note that you should remove the compiler and liker flags again from your project settings to have your other Metal sources compile properly again.)