[IOS Metal]使用METAL自定義CIFilter導(dǎo)致vertex function找不到的問題

通常使用 CIFilter 可以對(duì)圖像做一些處理巡莹,如果有些效果我們不滿意励稳,我們需要自己去實(shí)現(xiàn)的話刨秆,是可以通過寫 metal 來自定義 CIFilter,和 fragment shader 類似份蝴,處理對(duì)象都是一個(gè)像素點(diǎn)犁功。

如何使用 metal shader 自定義 CIFilter 網(wǎng)上的教程有很多,我這里還是贅述一下婚夫。

第一步:創(chuàng)建一個(gè).metal文件浸卦,定義 filter。記住自己的方法名案糙,后面需要用到限嫌。
第二步:繼承 CIFilter 定義出一個(gè)子類靴庆,通過加載 default.metallib 找到對(duì)應(yīng)的方法即可。
第三步:在 Build Settings 里面加入兩個(gè)flag怒医。

下面是第一步的代碼炉抒,隨便定義一個(gè)文件比如叫 kernel.metal,里面放上這些代碼稚叹。注意到這里的方法名是 myColor焰薄。

myColor 方法就是簡(jiǎn)單的返回當(dāng)前點(diǎn)的顏色。

#include <metal_stdlib>
#include <CoreImage/CoreImage.h>

using namespace metal;

extern "C" {
    namespace coreimage {
        
        float4 myColor(sample_t s, float value) {
            return s.rgba;
        }
    }
}

第二步扒袖,建立一個(gè)自己的 CIFilter 子類塞茅,然后做下面這些事情。

class CustomFilter : CIFilter {
    
    var value: Double = 0
    
    private var kernel: CIKernel!
    
    override init() {
        super.init()
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        // 找到默認(rèn)的 default.metallib
        guard let url = Bundle.main.url(forResource: "default", withExtension: "metallib"),
            let data = try? Data(contentsOf: url) else {
            fatalError("Unable to get metallib")
        }
        
        // 從lib中加載到 myColor 方法
        guard let myKernel = try? CIKernel.init(functionName: "myColor", fromMetalLibraryData: data) else {
            fatalError("Unable to create CIKernel from myKernel")
        }
        
        kernel = myKernel
    }
    
    var inputImage:CIImage?
    override var outputImage: CIImage? {
        let src = CISampler(image: self.inputImage!)
        // apply 這個(gè) filter
        return kernel.apply(extent: inputImage!.extent, roiCallback: { _, rect in return rect}, arguments: [src, value])
    }
}

第三步,在 Build Setting 里面加入 flag

需要加兩個(gè)參數(shù)一個(gè) -fcikernel逆巍,另一個(gè)是 -cikernel。這篇文檔第10頁有講 https://developer.apple.com/metal/MetalCIKLReference6.pdf 照著加一下即可。

好耶堪滨,自定義的 CIFilter 可以使用了,BUT鳖粟,此時(shí)此刻你之前寫的 pipeline 卻無法正常工作了禾唁,會(huì)提示找不到vertex function。

為什么會(huì)這樣呢迟蜜?因?yàn)榧恿?flag 之后刹孔,編譯的時(shí)候會(huì)將所有的 .metal 文件都通過某種形式進(jìn)行特殊的編譯使之成為適合 CoreImage 框架使用的代碼,正常的 pipeline 里面需要的 vertex shader 和 fragment shader 都失效了娜睛。

為了解決這個(gè)問題髓霞,需要將區(qū)分哪些是需要經(jīng)過 -cikernel, -fcikernel flag 打包的,哪些是不需要的畦戒。

這里有解決方案:https://stackoverflow.com/questions/57391441/metal-vertexfunction-defined-in-metal-file-becomes-nil-once-setting-compiler-a

我踩了不少坑才完成這項(xiàng)功能方库。

其實(shí)在 https://developer.apple.com/metal/MetalCIKLReference6.pdf 文檔中已經(jīng)寫了如何編譯 metal 使之成為kernel適用的代碼,見下圖

原理就是如此障斋,所以我們第一步需要區(qū)分 正常的metalcikernel的metal纵潦,為了區(qū)分這一點(diǎn),直接將剛剛寫的 kernel.metal 的后綴改為 .kernel垃环。這樣普通的metal文件仍然是 *.metal邀层,而為 CIFilter 用的 metal 文件后綴則是 .kernel

第二步遂庄,編譯前需要改回 .metal 后綴寥院,經(jīng)過實(shí)踐發(fā)現(xiàn),metal編譯器直接忽略了后綴名不正確的文件以至于無法編譯成功涛目,所以我們需要先執(zhí)行一個(gè) cp 步驟秸谢。

第三步经磅,執(zhí)行如上圖所示的編譯,變成一個(gè)我們自定義的 xxxx.metallib

第四步钮追,將 xxxx.metallib 復(fù)制到打包路徑中预厌,以便打包的時(shí)候可以打進(jìn)ipa文件。

第五步元媚,在自定義的 CIFilter 中加載metallib時(shí)轧叽,使用剛剛自定義的 xxxx.metallib,而不是 default刊棕。

現(xiàn)在來講講具體操作炭晒。

在 Build Rules 中添加一個(gè)步驟

在里面的輸入框中放入

# 復(fù)制一下,不然metal編譯器不認(rèn)識(shí)
cp "${SRCROOT}/Varlens/Shader/kernel.kernel" "${DERIVED_FILES_DIR}/kernel.metal"

# 后面這兩句就是編譯了甥角,注意輸入輸出路徑即可
xcrun metal -fcikernel "${DERIVED_FILES_DIR}/kernel.metal" -c -o "${DERIVED_FILES_DIR}/MyKernels.air"
xcrun metallib -cikernel "${DERIVED_FILES_DIR}/MyKernels.air" -o ${DERIVED_FILE_DIR}/kernel.metallib

然后在 Build Phases 中添加一個(gè)步驟网严,做復(fù)制 metallib 的操作。


完事嗤无。

krosshj @ 2021-04-22 14:57

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末震束,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子当犯,更是在濱河造成了極大的恐慌垢村,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚎卫,死亡現(xiàn)場(chǎng)離奇詭異嘉栓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拓诸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門侵佃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奠支,你說我怎么就攤上這事馋辈。” “怎么了胚宦?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵首有,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我枢劝,道長(zhǎng)井联,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任您旁,我火速辦了婚禮烙常,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己蚕脏,他們只是感情好侦副,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著驼鞭,像睡著了一般秦驯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挣棕,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天译隘,我揣著相機(jī)與錄音,去河邊找鬼洛心。 笑死固耘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的词身。 我是一名探鬼主播厅目,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼法严!你這毒婦竟也來了损敷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤渐夸,失蹤者是張志新(化名)和其女友劉穎嗤锉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墓塌,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年奥额,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苫幢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡垫挨,死狀恐怖韩肝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情九榔,我是刑警寧澤哀峻,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站哲泊,受9級(jí)特大地震影響剩蟀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜切威,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一育特、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧先朦,春花似錦缰冤、人聲如沸犬缨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怀薛。三九已至,卻和暖如春迷郑,著一層夾襖步出監(jiān)牢的瞬間乾戏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工三热, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鼓择,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓就漾,卻偏偏與公主長(zhǎng)得像呐能,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抑堡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容