GPU通用計算API的變遷和趨勢
在高性能計算、機器學習等現代應用領域中,GPU(Graphics Processing Unit)是占統治地位的計算引擎。GPU從早期的固化邏輯實現、到可編程、到今天的通用計算架構(GPGPU),其應用接口(API)隨著功能和通用性的提升而變得越來越靈活和高效。
1. 圖形渲染:DirectX 和 OpenGL
早期的GPU有渾名顯卡也不冤枉。從軟件角度來說,其邏輯架構基本上就是圖形的三角形坐標變換、頂點照明、像素著色等一係列功能。因為邏輯固化、功能單純,應用程序通過驅動接口可以直接執行這些功能,主要API就是較早版本的OpenGL和DirectX。
OpenGL源於曾經非常風光的SGI公司,然後演進成支持跨平台圖形的工業標準,版本也從最初的1.x,到2.0,3.x,到今天的4.5【1】。目前Khronos Group(OpenGL標準化組織)正在推進OpenGL5.0。而DirectX是微軟的windows平台上專用API。DirectX圖形API最初的幾個版本基本上是奮力直追OpenGL的features,直到DirectX 9.3c,微軟才完成了實質上的超越。DirectX 9.3在features上大致相當於OpenGL3.3。(注意,OpenGL分為台式、嵌入式兩個不同的profile,其版本之間的一一對應關係不甚明顯)
隨著圖形算法的改進和對高質清晰畫麵的追求,GPU需要越來越強大的靈活性來支持紋理、材料屬性、和精細度渲染,固化的邏輯顯然無法跟得上這些需求。GPU實現真正意義上的可編程是支持高層渲染語言(shading language)。對應於OpenGL的高層語言是GL Shading Language(簡稱GLSL),對應於DirectX的高層語言是High Level Shading Language (或HLSL)。GPU的可編程流水線架構如下:
由上圖可見,在GPU的邏輯流水線上,隻有兩個階段是可編程的,其它的仍然是固化的硬件支持。其中,一個可編程的stage是三角形頂點處理器(vertex processor),用戶可以根據自己的需求編寫適當的坐標變換、光線照明等複雜程序。另一個是像素處理器(fragment processor),實現更細節的渲染和紋理映射等。兩個處理器對應的GPU程序分別叫做vertex shader 和fragment shader。在DirectX中,fragment shader叫做pixel shader。
不同的GPU廠商對上述的可編程邏輯單元有不同的的硬件實現。比如,英偉達(Nvidia)早期的GeForce 係列,ARM Mali GPU都采取了離散架構,即vertex processor和fragment processor是獨立的物理處理單元。英偉達直到GeForce 8 係列的Tesla微架構,才改成了歸一化的GPU架構【2】,即統一的處理器可以同時執行vertex shader 和fragment shader。ARM Mali Midgard和最近的Bifrost微架構也采用了歸一化的實現【3】。不過,高通(Qualcomm)的Adreno GPU一開始就是歸一化的微架構。
2. 通用計算:DirectX、OpenGL/OpenCL和Renderscript
在DirectX9.3 實現超越之後,微軟在GPU API方麵一直處於領跑地位。隻是DirectX 10時運不濟,幾乎隨著Windows Vista灰飛煙滅。但之後的DirectX 11改頭換麵,並率先推出了細分曲麵(tessellation)和通用計算(compute)API,實現了從GPU 到GPGPU(general-purpose GPU)的飛躍【4】。
雖然從API的角度,通用計算處理器似乎是一個獨立的單元,但一般的GPU物理實現都是重複利用流水線上的可編程單元(歸一化的處理器),在執行通用計算GPU程序(叫做compute shader)時忽略其它的硬件功能。Vertex shader,fragment shader,和compute shader采用歸一化的編程模型。
因為DirectX是微軟的專用API,OpenGL社區也不甘落後,很快就推出相應的OpenGL通用計算和細分曲麵功能。為了有別於DirectX,OpenGL的tessellation 程序叫做tessellation control shader和tessellation evaluation shader,分別對應於DirectX的Hull shader和Domain shader。OpenGL ES(嵌入式係統)在3.1版本引進了通用計算,但直到去年的3.2版本才正式加入tessellation功能(在此之前由Google的擴展包得以維係)。
真正跨平台的通用計算API是Khronos的OpenCL1.x 和隨後的OpenCL2.x。感覺比較別扭的是,同一個Khronos Group標準化組織,卻同時有兩套通用計算API。簡單的理解是,OpenCL是為大計算準備的(heavy-duty compute),比如在GPU上的大規模高性能科學計算。OpenGL compute是輕量級的,適合於簡單的圖形、圖像處理等任務。例如,在模擬粒子係統時,用OpenGL通用計算API來計算速度、位置、勢能等,再快速切換到渲染模式,把整個粒子係統顯示出來。相比之下,OpenCL需要比較複雜的set-up,而且和圖形渲染之間的相互切換(inter-op)也有較高的執行開銷。
需要強調的是,OpenCL雖然是從GPU領域誕生出來,但通用計算框架遠不止適用於GPU。同樣可以應用在CPU,DSP,FPGA,或其它異構計算的體係架構中。OpenCL在跨平台的功能移植性(functional portability)方麵是很好的,但是其性能移植性(performance portibility)往往並不理想。
另一個算是常用、但並不被大多數人知道的通用計算API是Google推出的RenderScript。Google一開始是希望能像DirectX一樣,同時支持圖形渲染和通用計算。但很快發現,圖形渲染抵不過OpenGL,便丟下了渲染,專注於通用計算。所以有人開玩笑說,RenderScript既不是render也不是script。目前,RenderScript主要用在安卓係統中,隻有Google自己的應用在使用。但隨著下一代通用計算API的發展,RenderScript前途未卜。
3. 下一代API:一場“幾乎零開銷驅動”的競爭
阿裏的許多業務app在手機端上執行,對GPU的使用一般都是輕量級的。但隨著業務功能的增強,特別是AI和機器學習應用的普及,在端上的計算越來越多。之前的圖形渲染、通用計算API,不管是OpenCL和OpenGL,還是Renderscript,驅動開銷(driver overhead)都比較高。所以提高端上GPU功效、增加電池續航能力是移動GPU的當務之急。即使是在數據中心,能降低驅動程序的開銷,提高服務器CPU/GPU效率,對能源、硬件資源的節省也可以帶來可觀的效益。所以近兩三年來,工業界在研究如何降低GPU驅動上投入了大量的人力物力。幾大巨頭紛紛加入了所謂的“幾乎零開銷驅動”(almost zero overhead driver,AZOD)的競爭。
- 蘋果的Metal API,主要用在iOS和MacOS上
- 微軟的DirectX 12,當然還是聚集在windows係統中
- 超微(AMD)推出了Mantle
- Google 也有自己的版本(出於公司的秘密,隱去其名)
- Khronos Group跨平台的Vulkan
經過一番混戰和討價還價,競爭的結果就是AMD和Google各自把自己的ideas和框架工作捐給了Khronos,融合、演變成了現在的Vulkan 1.0。笑到最後的是蘋果Metal和微軟DirectX 12專用API,以及Khronos Group的跨平台通用Vulkan API。實質上,這三個API的features都是大同小異。
當然,AZOD並不能魔術般的讓驅動程序開銷一掃而光。他們在實現層麵上主要集中在以下幾點:
- 減少GPU在命令序列中的狀態更新、同步等開銷
- 重複使用命令包,並允許增量更新(incremental update)
- 實現多個渲染目標的融合,減少GPU數據的導入、導出
- non-binding 紋理等資源的使用
- 把內存管理、多線程管理等繁瑣的任務推到用戶層;用戶本來就有更好的全局觀來管理資源的生命周期
- 把GPU程序(shaders)的編譯工作在線下預處理,降低在線編譯的開銷
再稍微介紹一下Vulkan:
如果想理清Vulkan和OpenGL的關係,可以把Vulkan看成是下一代的OpenGL,即OpenGL 5.0。在Vulkan的命名上,除了希臘神話中的強大火神外,還有5的意思(羅馬數字V)。同樣,Vulkan也有一個附帶的編程語言,叫做SPIR-V (standard portable intermediate representation,SPIR)。V既是5,也是針對Vulkan。不過,SPIR-V在語言的定義上,遠超出了圖形的範疇,有能力表述通用計算、甚至C++的功能。現在有不少開源項目是基於SPIR-V,以得到更好的移植性。
4. 後記
上文提到,Khronos Group工業標準有兩套通用計算API,OpenCL和OpenGL(加上一個新的Vulkan)。這兩套API到底是什麼關係呢?正所謂,天下大勢,分久必合。目前的解決思路主要有兩個:
- 淘汰OpenCL,把其功能和某些特性引入到Vulkan中
- OpenCL作為上層API,用Vulkan在底層來實現OpenCL的功能
第二個想法與C++/C的關係有點像。C++可以作為與C無關的獨立語言,但C++的功能往往可以用C來具體實現。雖然Khronos 標準組織還沒有對外公開最後的答案,感覺這個方案可能會通過。
旁白
本文有意回避了把CUDA作為通用計算API的討論。嚴格意義上講,CUDA是一個GPU的軟件生態係統,且隻限於英偉達的GPU架構。所以和DirectX或RenderScript還是有區別的。
參考文獻
- https://www.khronos.org/opengl/wiki/History_of_OpenGL
- https://en.wikipedia.org/wiki/List_of_Nvidia_graphics_processing_units
- The Bifrost GPU architecture and the ARM Mali-G71 GPU
- https://en.wikipedia.org/wiki/DirectX
最後更新:2017-07-06 00:02:18
上一篇:
“淘寶心選”上線!taobaoxinxuan.xin被阿裏巴巴收購
下一篇:
打造雲上代碼交付鏈,CodePipeline實踐分享
[WCF安全係列]談談WCF的客戶端認證[用戶名/密碼認證]
MSSQL-應用案例-SQL Server 2016基於內存優化表的列存儲索引分析Web Access Log
tomcat6.0必須jdk5.0 以上才能運行
iphone7被鎖了id怎麼辦 蘋果8plus蘋果id已鎖定怎麼解除
7月12日雲棲精選夜讀:遊戲行業DDoS 6年談 什麼樣的架構才可以對DDoS免疫?
我變成了一名比特幣挖礦工
利用Android 2.2新特性完成縮略圖
如何打造支撐百萬用戶的分布式代碼托管平台
重慶首輛“免費WiFi公交”上街
現代汽車揭秘研發進展:ADAS、自動駕駛、V2X和未來出行的現狀和創新