最近因為工作的關係需要了解Vulkan,雖然還稱不上專家,不過對於Vulkan基本的原理有一些了解,同時因為之前接案的關係,有使用過NVN來寫程式,NVN其實算是Nvidia版本的Vulkan,所以也算有那麼一點實作經驗。本來今年TGDF我想投稿Vulkan Overview的,後來一忙起來就錯過截止時間了,所以改成在這邊分享一下。基本上我不會講到很技術性的內容,只會講到概念,所以即使不是工程師背景的製作人也可以了解到使用Vulkan的好處在哪,評估一下自己的專案到底需不需要用到Vulkan。
Vulkan就像OpenGL或是D3D一樣是一個繪圖API,它的目的是為了解決一些舊有繪圖API的效率問題。OpenGL是1992發展出來的API,距今已經27年了,而這幾年GPU進展速度越來越快,可以想見的是OpenGL已經完全無法跟上硬體進步的速度了。D3D雖然較新,因為微軟一家掌控而得以進步較快,但他是有些效率問題無法克服,所以微軟才會推出D3D 12,其實就等於微軟版本的 Vulkan。而蘋果也推出Metal,其實都跟Vulkan一樣是要解決現有繪圖API跟GPU設計脫節的問題。其中最大一個問題就是GPU其實是一個非常多工的設計,而現有的繪圖API都是single thread的設計,所以為了要維持住這個single thread的假象,driver必須做非常多的工作以及猜測,也因此造成driver複雜度太高,效率不佳,以及不同driver會有不同行為的問題。Vulkan的推出就是為了解決這一個問題,讓繪圖API趨近於真正GPU的運作方式,同時也因應現代化GPU的設計加入一些舊時代API無法做到的功能。
除了更接近GPU的運作方式之外,Vulkan設計的另一個理念是讓application跟driver不要再有重複的工作以及猜測,所以Vulkan的設計是非常接近底層的,同時也是非常明確的,在使用Vulkan後,不會再有driver的black box,所有GPU的操作都需要藉由API明確的指定,也不會有像OpenGL有所謂的預設值,沒有明確指定所有該有的設定下場就是crash或是undefined behavior。因為如此,driver就變得非常薄了,而application要負擔起從前driver會處理的大部分工作,像是記憶體配置以及工作之間的同步。也因為如此,Vulkan程式是又臭又長的,一個Hello Triangle就需要將近一千行的C++ code。所謂能力越大責任越重,想要完全掌控GPU勢必要付出一點代價 XD
Vulkan Layers (https://vulkan.lunarg.com/doc/view/1.0.54.0/windows/LoaderAndLayerInterface.html)
Vulkan還有一個特殊設計叫做layer,layer是在application呼叫跟Vulkan ICD中間的代理人。這個設計有趣在於layer可以是0個也可以是很多個,其實有點像是DLL hooker,但是因為是設計在API level,因此有一個跨平台的標準在,相對hooker容易許多,也可以開發第三方的 layer。而Vulkan本身也利用了這個特性,因此API本身幾乎沒有錯誤檢查,而是將錯誤檢查寫成validation layer,因此在application的開發階段可以插入validation layer來回報錯誤,等到appication進入release階段就可以直接抽掉validation layer,讓appication不用再去浪費時間檢查根本不存在的錯誤了。
這也是一個迷思,雖然Vulkan比OpenGL有效率又明確,但並不代表換成Vulkan你的application就必然會變快。Vulkan解決的是API效能不彰的問題,但如果你的app本身就沒有API的效率問題,那在同樣的硬體之下,你的app也是不可能因為改用vulkan就變快的。如果你的app本身是因為API的呼叫效率問題導致CPU bound,這時改用Vulkan才有變快的可能。另一個變快的可能是使用Vulkan的API來做到舊有API無法達到的pipeline改變,比如說multi-thread rendering或是善用render pass來改善rendering pipeline。
目前幾乎所有的mobile GPU為了省電都是使用tile-based 設計。而這也是Vulkan的一個強項,在Vulkan中有對render pass, render subpass的設計,這些設計對tile-based GPU是非常必要的,而在OpenGL中卻是沒有對應的API,所以導致很多時候driver需做很多猜測,也導致了driver的效能難以預測。如果你用tile-based GPU所提供的工具去觀察你app的rendering pipeline,你會發現原本你以為的single rendering pipeline,其實被driver拆成好幾個render pass,而render pass越多,效能可能就越低落。
同步問題大概是使用Valkan時最棘手的問題了,因為之前這些問題都是driver幫忙處理掉,而現在要由app本身100%負責了。同步用的好,可以讓app完全利用到多CPU核心以及GPU高度平行處理的好處,但是要是用不好,就可能導致Vulkan比OpenGL還要慢的狀況。而Vulkan的同步可以分為CPU跟GPU同步以及GPU內部工作間的同步,而要將同步用得好,對GPU硬體運作原理的理解就是不可或缺的知識。