Extract common functionality in Core Image Metal files

In his talk "Build Metal-based Core Image kernels with Xcode", David presents the build phases necessary to compile Core Image Metal files into Metal libraries, that can be used to instantiate CIKernels.
There is a 1-to-1 mapping between .ci.metal file and .ci.metallib file. I also found that the Metal linker doesn't allow to link more then one .air file into one library when building for Core Image.

This works fine until I want to have some common code (such as math functions) extracted into another file to be used by multiple kernels. As soon as I have two color kernels (that get concatenated during filter execution) that use the same shared functions, the runtime Metal compiler crashes (I assume because of duplicate symbols in the merged libraries).

Is there a good way to extract common functionality to be usable by multiple kernels in a pipeline?
Answered by Graphics and Games Engineer in 615838022
Thank you for your question. Please file a report via the Feedback Assistant to fix the compiler crash you are seeing.

First, it is ok to have multiple cikernel functions in one .ci.metal file, along with their common helpers. They would collectively compile into a single .metallib file for CoreImage to load.

With multiple metal files: Although David's talk shows a technique with one .ci.metal per .metallib, the linker introduced with the new Metal Developer Tools can link multiple .ci.air files into a single .metallib file, allowing you to factor and separately compile your common code. The necessary link command is metal -fcikernel ...air. A simple way to achieve that is to create a target of type Metal Library and to augment its Build Settings with:
  • In "Metal Compiler - BuildOptions" -- MTL_COMPILER_FLAGS : -fcikernel

  • Add "User-Defined" -- MTLLINKER_FLAGS : -fcikernel

Thank you for your question. Please file a report via the Feedback Assistant to fix the compiler crash you are seeing.

First, it is ok to have multiple cikernel functions in one .ci.metal file, along with their common helpers. They would collectively compile into a single .metallib file for CoreImage to load.

With multiple metal files: Although David's talk shows a technique with one .ci.metal per .metallib, the linker introduced with the new Metal Developer Tools can link multiple .ci.air files into a single .metallib file, allowing you to factor and separately compile your common code. The necessary link command is metal -fcikernel ...air. A simple way to achieve that is to create a target of type Metal Library and to augment its Build Settings with:
  • In "Metal Compiler - BuildOptions" -- MTL_COMPILER_FLAGS : -fcikernel

  • Add "User-Defined" -- MTLLINKER_FLAGS : -fcikernel

Thanks for the fast reply!

I tried your suggestion for building a single metallib, which was easy since I already had this setup (with the "old" -cikernel flag for the Metal linker).

It seemed to work at first, but then I noticed that not all kernels get compiled (and hence also not found on CIKernel.init) into the resulting library. I found that kernels that have a coreimage::sampler as input parameter seemingly won't get compiled this way.
They do get compiled, however, when using the other .metal -> metal -c -> .air -> metallib -> .metallib (so using metallib for linking) toolchain.

I already filed feedback for this including a minimal sample project (FB7795164).
It would be great if you'd find the time to look into this.

Thanks!
I also created sample code and filed another Feedback for the concatenation issue (FB7796293).
Extract common functionality in Core Image Metal files
 
 
Q