U4 內核 WebGL 支持發展方向

本文主要描述 U4 內核對 WebGL 支持的後續可能發展,完善對Hilo3D引擎的支持,一些可能的工作事項,分為「性能」,「兼容性」和「新特性」三個方面。

1. 性能

1.1 JS 引擎優化

通過測試發現新版的 v8 引擎在特定 Demo (fog)下比目前 U4 2.0(M57)的 v8 引擎在性能上有接近 20% 左右的性能提升。

同事的分析如下:

Hilo3d.js裡面使用了webpack這個架構。webpack的函數d使用Object.defineProperty定義對象的property的getter。常常調用的函數multiply使用webpack的d函數定義如下: __webpack_require__.d(mat2_namespaceObject, "multiply", function() { return multiply; });

相當於使用Object.defineProperty為mat家族定義了property multiply。57版本的 v8處理這種類型的property的時候,潦草的是使用了slow stub。因此頻繁的退出到c++ native代碼出處理這種情況。之後的v8會使用正確對待這種類型的property。

從方法跟蹤的情況來看,57 跟 62 最明顯的差異在於 V8.Builtin_HandleApiCall 和 V8.Runtime_Runtime_KeyedGetProperty 的調用,在 62 上只有 57 的一半左右。

我們希望通過優化目前的 v8 引擎來提升這一部分的性能。

1.2 Hilo3D CPU Bound 優化

通過對若干 Hilo3D Demo 的性能分析發現,實際上不少 Demo 的性能瓶頸主要在 CPU 而不是 GPU。也就是說制約幀數上限的是 JS 調用部分的 CPU 耗時而不是實際 GL 繪製的 GPU 耗時。

我們希望可以通過找出 CPU Bound 的瓶頸,在 Hilo3D 引擎端和應用端進行優化。另外使用 WebAssembly 對一些頻繁調用的耗時 JS 運算比如矩陣運算進行優化也是一個可能的方向。

移動端的 JS 性能是一個很嚴重的問題,PC 端的模擬測試完全無法檢測出來。

1.2.1 WebAssembly

初步驗證的結果,WebAssembly 的一個手寫位元組碼的簡單 Demo 和另外一個編譯 C/C++ 代碼生成的 Demo 在 U4 2.0(M57)上都是可以正常運行的。

當前 WebAssembly 的開發有兩種方式:一種就是自己手寫位元組碼,自己管理內存的分配和釋放;一種是編寫 C/C++ 代碼,然後使用 Emscripten 編譯成 wasm 位元組碼,Emscripten 會自動生成相應的膠水代碼(接近 50kb,包括部分 C 庫的實現,比如內存分配和釋放 - malloc & free);前者自然沒有太大的可行性。

理論上我們應該可以把目前 Hilo3D 使用的 glMatrix 庫改成使用 WebAssembly 的版本,不過重要的是,如果是簡單的數組/矩陣運算,WebAssembly 的版本性能上跟 v8 JIT 後生成的 Native Code 性能基本上是一致的,所以單純把部分簡單運算 WebAssembly 化恐怕沒有多少價值(如果運算是比較適合使用 SIMD 的話倒是有可能會通過 SIMD 帶來性能的提升,不過 WebAssembly 對 SIMD 的支持好像還在開發階段),還要面臨如何適配 WebAssembly 內存管理模型的問題(JavaScript 的代碼需要管理 malloc 分配的指針,然後在不使用後釋放,如果沒有正確釋放就會導致內存泄露)。

對 mat4.multiply JavaScript 版本和 WebAssembly 版本性能測試對比的結果,U4 2.0 在 Nexus6 上面調用 10000 次的耗時:

  1. WebAssembly: 基本穩定在 2.5 毫秒以內;
  2. JavaScript(JIT):大部分情況下在 2.5 ~ 3 毫秒之間波動,偶爾會有較大波動(可能是觸發GC?);

另外 WebAssembly 官方的整體進度上還處於 Runtime 和 Toolchain 的開發階段,目前並沒有找到任何 WebAssembly 的官方庫或者第三方庫的支持,也沒有找到一些成功的應用範例,官網上連個複雜點的 Demo 都欠奉... 總而言之還是處於十分原始的階段

從目前來看,WebAssembly 會比較適合在大數據量,高運算複雜度的數字信號處理領域的應用,這裡一個 ARToolkit 項目有使用到 WebAssembly。

1.2.2 CPU Bound

目前的測試發現 Hali3D 比較容易出現 CPU Bound 的情況,特別是對於場景存在多個物件(Mesh 或者 Instanced Meshes)的情況下,WebGLRenderer.render 耗時嚴重的現象比較突出。

後續可以進行更深入的分析研究從引擎/應用的角度有沒有優化的空間。

1.3 Chrome 獨立 Window 和 GPU 進程的渲染架構

同 2.2。

1.4 Offscreen Canvas

同 3.2。

2. 兼容性

2.1 軟 GL

軟 GL 的方案就是使用第三方庫,使用 CPU 來模擬 GL。之前跟 Chrome 團隊的交流,Chrome 並沒有在移動平台採用這種方案的打算。一是因為移動平台 CPU 的限制,無論是性能還是正確性都很難保證;二是存在 GL 兼容性的機型,基本上都是硬體或者系統版本比較舊的機型,隨著移動硬體和系統的發展,相應的問題會越來越少。

我們基本上也贊同這樣的看法,即使打算使用軟 GL,也是建議在應用層而不是在內核來實現,內核的實現受限於當前 WebView 的渲染架構(缺少獨立的 Window),理論上性能會比應用層更糟糕,另外考慮可能增長的 Binary Size,可行性就更低了。

2.2 Chrome 獨立 Window 和 GPU 進程的渲染架構

Chromium 在 Android 平台上實際有兩套渲染架構,分別是 WebView 和獨立應用的 Chrome,主要的區別是前者走的 Android View Rendering 的渲染流程,而後者有自己獨立的 Window(SurfaceView)和 GPU 進程,網頁的繪製是完全獨立的,不走 Android View Rendering 的渲染流程。

如果網頁是在一個全屏窗口打開(除了標題欄就沒有其它 UI 元素)而不是內嵌到一個複雜的 View 樹上,並且是運行在一個獨立的進程,理論上,我們是可以走 Chrome 的渲染架構的。

從兼容性的角度來看,Chrome 的渲染架構可以獲得更好的兼容性:

  1. WebView 是否可以使用硬體加速會受限於應用的 Window 是否使用硬體加速,而使用獨立 Window 的Chrome 不受這個限制;
  2. 獨立 GPU 進程,GPU 驅動的崩潰只會導致當前網頁無法顯示,不會導致整個應用的崩潰,影響相對比較小,所以我們也可以進一步放開特定機型黑名單的限制;

另外 Chrome 的渲染架構在整體性能上也有一定的優勢,它避免了 Android View Rendering 的額外開銷和在渲染流水線調度上更靈活。

我們測試了全部 threejs 的 Demo,其中不到 15% 的 Demo 會有較明顯差距(> 10%),下面的對比數據是在一台性能較差的設備上測試的結果(紅米 Note,Android 4.4),理論上在性能較好的設備和 Android 5.0+ 的系統,性能差距還會進一步減少。初步的結論是 Chrome vs WebView 在部分場景下有輕微優勢。

3. 新特性

3.1 WebGL 2.0

首先,U4 2.0(M57)對比 U4 1.0(Chrome 是從 M56 開始支持 WebGL 2.0),內核是支持 WebGL 2.0 API 的,可以通過這次測試頁面驗證,但是 M57 在 Android 上對 WebGL 2.0 的支持不完善,原生的代碼通過黑名單禁用了。

但實際上因為 M57 原生代碼的不完善問題,WebGL 2.0 的黑名單實際在 WebView 上不生效(後續代碼已經修復),所以 M57 WebView 是可以繞過黑名單的限制使用 WebGL 2.0 的,雖然存在風險。如果實際投入使用,需要考慮合併後續的 Patch。

WebGL 2.0 具體是否支持還要取決於硬體本身,需要 GPU 驅動需要支持 ES 3.0,所以 WebGL 2.0 的使用需要從引擎/應用端考慮做降級處理。

目前對性能有提升的兩個特性 Veterx Array Object 和 Instanced drawing,Hilo3D 已經通過 WebGL 1.0 的擴展支持了。壓縮紋理是一個收益明顯(內存佔用和內存帶寬佔用),也比較容易降級處理的特性,後續 Hilo3D 也可以考慮支持。

3.2 Offscreen Canvas

Offscreen Canvas 是一個有助於頁端編寫多線程並發的 Canvas/WebGL 引擎/應用的新特性。在今年的 Google I/O 上,Chrome 團隊的工程師也重點介紹了這一特性。

通過 Offscreen Canvas,頁端可以把大量的 JS 調用轉移到 Worker 線程,避免內核主線程的阻塞,實現更高的並發程度,可以有效緩解 CPU Bound 導致的幀數限制的狀況。另外 Offscreen Canvas 不受硬體限制,只要內核支持就可以使用,不需要考慮機型兼容性問題,所以也更有價值。

理論上,如果頁面包含越多非 WebGL 的元素,使用 Offscreen Canvas 通過並發來減少內核主線程的佔用對性能的提升就越有幫助。

Offscreen Canvas 目前 Chrome 還在開發中,建議後續持續關注。


推薦閱讀:

WebAssembly 系列(三)編譯器如何生成彙編

TAG:WebGL | WebAssembly | 浏览器内核 |