天天看點

備胎計劃002 跨平台shader編譯方案實踐

Unity 和 Unreal 作為流行的商業引擎,引擎這個東西,最主要的特點就是抽象。其中關于Shader部分,他們都做了比較好的抽象,使用者不需關注每個平台的shader不同,寫一次,build各個平台。

這是當今遊戲引擎的一個重要标配,Unity 和 Unreal 都自己做了大量的工作,網上也有人分析過Unity和Unreal各自的方案。

替代方案

現如今,開源世界也有一些方案來處理這個問題了

主要是兩條線

1.DirectXShaderCompiler + spirvcross

2.glsllang +spirvcross

方案一,DirectXShaderCompiler 是微軟開源的hlsl編譯器,最新的版本增加了一個編譯開關,重編譯後可擷取将hlsl 編譯為 spirv 的能力,然後通過spirvcross項目編譯成各種各樣的東西

方案二,glsllang 是 Khronos 官方的 for vulkan 的 glsl編譯器,他負責将glsl編譯為spirv,然後通過spirvcross項目編譯成各種各樣的東西

這兩個方案使用的編寫語言分别是hlsl 和 glsl(方案二其實也支援hlsl,但是資料比較少,我還沒有實驗出來),都是用sprivcross來跨平台

這裡就要解釋一下什麼是spirv

爺爺Khronos: 是圖形标準化組織,OPENGL就是他們制定的,然後在微軟搞dx12,蘋果搞metal的時候,他們也推出了新一代圖形API标準,就是Vulkan。

爹Vulkan:大伯OPENGL,二伯OPENGL ES

兒子spirv:而vulkan使用的shader二進制格式就是spirv

因為opengl 和opengles 的時代,都沒有發展二進制格式,爺爺制定标準的時候就想把他打造成一個通用的格式,是以spirv實際上是個很通用的執行格式(想象一下c#背後的IL)

而spirvcross也是爺爺開發的一個反編譯項目,專門把spirv反編譯成各種shader源檔案

https://github.com/KhronosGroup/SPIRV-Cross

官網上說他的功能是,(反編譯spirv)生成可讀的GLSL,蘋果MSL,HLSL,c++,json好了,天下大同了

  • Convert SPIR-V to readable, usable and efficient GLSL
  • Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
  • Convert SPIR-V to readable, usable and efficient HLSL
  • Convert SPIR-V to debuggable C++ [DEPRECATED]
  • Convert SPIR-V to a JSON reflection format [EXPERIMENTAL]

廢話不多說,咱們試試

實踐方案一

DirectXShaderCompiler 還要自己重編譯,麻煩(其實是我沒編譯通過…build.py寫的太爛了,辣雞微軟)

好在微軟直接給了個整合好的方案一

ShaderConductor

https://github.com/microsoft/ShaderConductor

根據文檔指導,直接下個最新的預發行版本就好

https://dev.azure.com/msft-ShaderConductor/public/_build/results?buildId=205&view=artifacts&type=publishedArtifacts

備胎計劃002 跨平台shader編譯方案實踐

下份windowsx64的回來,其它平台的我沒測試,都是指令行工具,大差不差。

寫一個test.hlsl

備胎計劃002 跨平台shader編譯方案實踐

然後執行指令行來編譯成glsl

備胎計劃002 跨平台shader編譯方案實踐

ShaderConductorCmd –I test.hlsl –E vs_main –S vs –T glsl –V 200

一長串的參數

-I test.hlsl 輸入檔案

-E vs_main 要編譯的函數

-S vs   編譯那種shader

-T glsl 輸出為glsl格式

-V 110 glsl版本号 ,glsl版本号

副GLSL版本号表

2.0 110

2.1 120

3.0 130

3.1 140

3.2 150

3.3 330

4.0 400

4.1 410

4.2 420

4.3 430

4.5 450

産生的ios_matal檔案

備胎計劃002 跨平台shader編譯方案實踐

産生的glsl檔案

備胎計劃002 跨平台shader編譯方案實踐

問題,因為這個方案裡的DXshadercompiler 是dx11的,是以這有個問題

備胎計劃002 跨平台shader編譯方案實踐

我單獨寫的uniform matView也被放進了cbuffer裡,觀看glsl就會發現有了語義變化,這就像卡了一根刺。

實驗方案二

下載下傳glsllang

https://github.com/KhronosGroup/glslang

有release下載下傳

https://github.com/KhronosGroup/glslang/releases

也下載下傳個x64的

下載下傳spirvcross

也有release下載下傳

https://github.com/KhronosGroup/SPIRV-Cross/releases

解壓出來就能用

這次寫glsl

備胎計劃002 跨平台shader編譯方案實踐

glsllang 預設使用檔案擴充名識别功能

vertexshader就要.vert結尾

備胎計劃002 跨平台shader編譯方案實踐

調用上述指令編譯test.vert 和 test.frag 分别是 vertexshader 和 fragmentshader

分别得到frag.spv 和 vert.spv檔案

這就是spirv的二進制格式shader

然後調用spirvcross 可以反編譯他們到不同的shader

備胎計劃002 跨平台shader編譯方案實踐

沒有參數就反編譯為glsl

加--hlsl就反編譯為hlsl

加--msl就反編譯為蘋果metal

還有一堆參數就得你自己研究了

生成的hlsl比較啰嗦

備胎計劃002 跨平台shader編譯方案實踐
備胎計劃002 跨平台shader編譯方案實踐
備胎計劃002 跨平台shader編譯方案實踐

生成的glsl就比較幹爽了

最後說兩句

目前我想要做的備胎,第一服務對象是Android(gl +vulkan)

第二才考慮 IOS \PC \web 這些

方案二明顯更加合适,使用glsl作為基準,對gl和vulkan環境支援良好,在第二考慮時才需要spirvcross上馬,可以支援dx 和 metal。

原理通了,接下去就是整合了。