GCanvas 提供了一套類似於 H5 Canvas 標準的 JavaScript API。基於這套 API 可以方便的去做圖形繪製、動畫渲染等,開發的體驗與 H5 Canvas 是完全一樣的。
GCanvas 介紹
GCanvas發展經歷了兩個階段。
- 第一階段,2014 年中到 2015 年底,解決 Android 平臺 WebView Canvas 渲染效能差的問題。
- 第二階段,2016 年 11 月到現在,為前端提供 Native 圖形繪製能力。
用一句話來概括 GCanvas,即遵循 W3C 標準,移動端的跨平臺的高效能圖形渲染引擎。可以從三個方面來解釋。
- 遵循 W3C 標準
GCanvas 提供了一套類似於 H5 Canvas 標準的 JavaScript API,開發人員基於這套 API 可以方便的去做圖形繪製、動畫渲染等。開發的體驗與 H5 Canvas 是完全一樣的。 - 跨平臺
GCanvas 的核心基於 OpenGL ES, 用 C++ 實現了一套用於描述 Canvas 標準 API 的介面實現。我們將其稱為渲染引擎核心。並通過交叉編譯,使得可以適配 Android、iOS 這兩大主流移動平臺,因而具有跨平臺的特性。 - 高效能
早期移動平臺上 H5 Canvas 去做一些複雜的動畫或遊戲,在 WebView 上的體驗非常差。 主要原因是 WebView 對 GPU 硬體加速的支援差。高效能則是充分利用了 GPU 硬體的渲染能力,主要體現兩個方面:- 對於 Android 3.0 以前的系統,Android 的渲染管線是不支援硬體加速的,WebView 中的 Canvas 不能獲得 GPU 的圖形渲染能力的支援。對於這類系統,通過 GCanvas 可以獲得更底層的 OpenGL ES 的硬體加速能力提高渲染效率。
- 鏈路上來看,縮短了呼叫路徑,提高了渲染效能。使用了 GCanvas 則不需要經過 WebView 內部的複雜邏輯處理和圖層樹渲染,而是讓 JavaScript 通過橋接方式直接呼叫渲染引擎核心(OpenGL ES)。
GCanvas 組成
如上圖所示 GCanvas 由三層組成 JavaScript 層、外掛層、核心渲染庫。
- JavaScript 層
JavaScript 提供對外統一的 API,支援 Canvas 2D 和 WebGL 的功能介面。介面支援情況請參考 API 覆蓋。 - 外掛層
外掛層核心包含三部分。- Bridge 橋接
JavaScript 到 Native 的橋接,比較主流的方式 JSBridge 和 JSBinding。JSBridge 實現方式,如 Cordva、WebviewJavascriptBridge 等。 還可以用 JSBinding 方式來實現,如 V8、JavascriptCore 等。實際的應用場景中這兩種橋接方式都有支援。 - 通用外掛
通用外掛包含了通用外掛介面與實現、GCanvas 的管理、渲染命令佇列管理、紋理快取等。支援不同型別橋接方式下的擴充套件。 - 系統適配
系統適配涉及 Android 和 iOS 對 OpenGL ES 實現的差異,網路圖片下載,字型渲染等方面。
- Bridge 橋接
- 核心渲染庫
核心渲染庫包括對外統一的介面,以及 Contex2D 和 WebGL 模組,底層則是對 OpenGL ES API 等分裝。
GCanvas 流程
上圖是 JavaScript 層渲染核心庫的概要流程,關鍵的兩個流程是初始化和渲染。
- 初始化
初始化,JavaSript 層獲取配置判斷執行環境,通過橋接層,外掛層完成檢視和 GCanvas 的建立。進一步完成對 OpenGL 環境的初始化。 - 渲染
渲染,JavaScript 層將所有的API呼叫託管,並且轉換成自定義的命令格式(命令型別 + 引數的組合)。渲染觸發則由 JavaScript 定時器觸發或者手動觸發的方式,將這些命令下發到渲染核心庫執行。
以 Weex 為例, 繪製圖形和圖片的測試程式碼如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<template> <div ref="test"> <gcanvas ref="canvas_holder" style="width:750; height:750; background-color:rgba(0, 0, 0, 0.1)"></gcanvas> </div> </template> <script> var GCanvas=require('weex-gcanvas'); var Image=require('weex-gcanvas/gcanvasimage'); module.exports = { mounted: function () { //1、初始化 GCanvas var ref = this.$refs.canvas_holder; var gcanvas = GCanvas.start(ref); var ctx = gcanvas.getContext('2d'); //2、執行渲染操作 //rect ctx.fillStyle = 'red'; ctx.fillRect(0, 0, 100, 100); //rect ctx.fillStyle = 'black'; ctx.fillRect(100, 100, 100, 100); ctx.fillRect(25, 210, 700, 5); //circle ctx.arc(450, 200, 100, 0, Math.PI * 2, true); ctx.fill(); //drawImage var image = new Image(); image.onload = function(){ ctx.drawImage(image, 100, 330); ctx.drawImage(image, 100+300, 330, 225, 75); } image.src = 'https://www.khronos.org/assets/uploads/ceimg/made/assets/uploads/apis/OpenGL-ES_100px_May16_225_75.png'; } }; </script> |
通過 Weex Playground 執行結果如下
具體分析下整個流程。結合外掛層和核心渲染庫來分析。
- 外掛層流程
以 iOS 為例分析,Android 的過程是類似的。- GLKView 檢視建立,並且與 GCanvas 物件建立繫結關係;
- GCVCommon,資源載入與紋理繫結;
- GCanvasPlugin,設定位置資訊、裝置比率、下發渲染命令;
- 渲染庫流程
渲染命令的解析,最終通過呼叫 OpenGL ES 的方法或組合方法來實現 Context2D 和 WebGL 的效果,生成幀快取,提交給 GPU 渲染,最後在繫結的 GLKView 檢視上顯示。
- Context2D,需要實現諸如 GPath、GTexture、GTransform、GTriangulate 等來實現 Canvas 的渲染效果;
- WebGL 相對簡單,WebGL1.0 的 API 基本都能與從 OpenGL ES2.0 找到與之相對應的 API;
GCanvas 測試例子
下面給出一些 GCanvas 的案例。
- GCanvas 與 H5 Canvas 效能對比
- Android 平臺,左邊是 GCanvas,右邊是 H5 Canvas。同屏渲染圖片越多,效能差異越明顯。
- Hilo 2D
100 條魚基於 Hilo 2D 動畫庫,滿屏魚的動畫測試。 - Chart 圖示渲染
Chart 圖示庫的渲染效果基於圖表庫,不同型別的圖表渲染測試。
附:GCanvas API 支援情況
最後附上 GCanvas Contex2D 和 WebGLAPI 的支援列表,支援常用的介面。另外,WebGL 的 API 目前正在做補全開發,後續會支援 WebGL1.0 API 的全覆蓋。
- Context2D API
API名稱 | API型別 | 狀態 |
---|---|---|
fillStyle | Attribute getter/setter | Implemented |
strokeStyle | Attribute getter/setter | Empty |
shadowColor | Attribute getter/setter | Empty |
shadowBlur | Attribute getter/setter | Empty |
shadowOffsetX | Attribute getter/setter | Empty |
shadowOffsetY | Attribute getter/setter | Empty |
createLinearGradient() | Method | Empty |
createPattern() | Method | Empty |
createRadialGradient() | Method | Empty |
addColorStop() | Method | Empty |
isPointInPath() | Method | Empty |
createEvent() | Method | Empty |
toDataURL() | Method | Empty |
lineCap | Attribute getter/setter | Implemented |
lineJoin | Attribute getter/setter | Implemented |
lineWidth | Attribute getter/setter | Implemented |
miterLimit | Attribute getter/setter | Implemented |
font | Attribute getter/setter | Implemented |
textAlign | Attribute getter/setter | Implemented |
textBaseline | Attribute getter/setter | Implemented |
globalAlpha | Attribute getter/setter | Implemented |
globalCompositeOperation | Attribute getter/setter | Implemented |
rect() | Method | Implemented |
fillRect() | Method | Implemented |
strokeRect() | Method | Implemented |
clearRect() | Method | Implemented |
fill() | Method | Implemented |
stroke() | Method | Implemented |
beginPath() | Method | Implemented |
moveTo() | Method | Implemented |
closePath() | Method | Implemented |
lineTo() | Method | Implemented |
clip() | Method | Implemented |
quadraticCurveTo() | Method | Implemented |
bezierCurveTo() | Method | Implemented |
arc() | Method | Implemented |
arcTo() | Method | Implemented |
scale() | Method | Implemented |
rotate() | Method | Implemented |
translate() | Method | Implemented |
transform() | Method | Implemented |
setTransform() | Method | Implemented |
fillText() | Method | Implemented |
strokeText() | Method | Implemented |
measureText() | Method | Implemented |
drawImage() | Method | Implemented |
createImageData() | Method | Implemented |
getImageData() | Method | Implemented |
putImageData() | Method | Implemented |
save() | Method | Implemented |
restore() | Method | Implemented |
getContext() | Method | Implemented |
loadTexture() | Method | Implemented |
unloadTexture() | Method | Implemented |
resetTransform() | Method | Implemented |
render() | Method | Implemented |
capture() | Method | Implemented |
resetClip() | Method | Implemented |
- WebGL API
API名稱 | API型別 | 狀態 |
---|---|---|
viewport() | Method | Implemented |
vertexAttribPointer() | Method | Implemented |
vertexAttrib2fv() | Method | Implemented |
useProgram() | Method | Implemented |
uniformMatrix4fv() | Method | Implemented |
uniformMatrix3fv() | Method | Implemented |
uniformMatrix2fv() | Method | Implemented |
uniform4iv() | Method | Implemented |
uniform4i() | Method | Implemented |
uniform4fv() | Method | Implemented |
uniform4f() | Method | Implemented |
uniform3iv() | Method | Implemented |
uniform3i() | Method | Implemented |
uniform3fv() | Method | Implemented |
uniform3f() | Method | Implemented |
uniform2iv() | Method | Implemented |
uniform2i() | Method | Implemented |
uniform2fv() | Method | Implemented |
uniform2f() | Method | Implemented |
uniform1iv() | Method | Implemented |
uniform1i() | Method | Implemented |
uniform1fv() | Method | Implemented |
uniform1f() | Method | Implemented |
texParameteri() | Method | Implemented |
texImage2D() | Method | Implemented |
shaderSource() | Method | Implemented |
scissor() | Method | Implemented |
renderbufferStorage() | Method | Implemented |
pixelStorei() | Method | Implemented |
linkProgram() | Method | Implemented |
lineWidth() | Method | Implemented |
getUniformLocation() | Method | Implemented |
getShaderParameter() | Method | Implemented |
getAttribLocation() | Method | Implemented |
generateMipmap() | Method | Implemented |
frontFace() | Method | Implemented |
framebufferTexture2D() | Method | Implemented |
flush() | Method | Implemented |
enableVertexAttribArray() | Method | Implemented |
enable() | Method | Implemented |
drawElements() | Method | Implemented |
disableVertexAttribArray() | Method | Implemented |
disable() | Method | Implemented |
depthMask() | Method | Implemented |
depthFunc() | Method | Implemented |
deleteTexture() | Method | Implemented |
deleteShader() | Method | Implemented |
deleteRenderbuffer() | Method | Implemented |
deleteProgram() | Method | Implemented |
deleteFramebuffer() | Method | Implemented |
deleteBuffer() | Method | Implemented |
cullFace() | Method | Implemented |
createTexture() | Method | Implemented |
createShader() | Method | Implemented |
createRenderbuffer() | Method | Implemented |
createProgram() | Method | Implemented |
createFramebuffer() | Method | Implemented |
createBuffer() | Method | Implemented |
compileShader() | Method | Implemented |
colorMask() | Method | Implemented |
clearStencil() | Method | Implemented |
clearDepth() | Method | Implemented |
clearColor() | Method | Implemented |
clear() | Method | Implemented |
bufferData() | Method | Implemented |
blendFuncSeparate() | Method | Implemented |
blendFunc() | Method | Implemented |
blendEquationSeparate() | Method | Implemented |
blendEquation() | Method | Implemented |
bindRenderbuffer() | Method | Implemented |
bindFramebuffer() | Method | Implemented |
bindBuffer() | Method | Implemented |
bindAttribLocation() | Method | Implemented |
attachShader() | Method | Implemented |
activeTexture() | Method | Implemented |
validateProgram() | Method | Empty |
texSubImage2D() | Method | Empty |
texParameterf() | Method | Empty |
stencilOpSeparate() | Method | Empty |
stencilOp() | Method | Empty |
stencilMaskSeparate() | Method | Empty |
stencilMask() | Method | Empty |
stencilFuncSeparate() | Method | Empty |
stencilFunc() | Method | Empty |
sampleCoverage() | Method | Empty |
readPixels() | Method | Empty |
polygonOffset() | Method | Empty |
isTexture() | Method | Empty |
isShader() | Method | Empty |
isRenderbuffer() | Method | Empty |
isProgram() | Method | Empty |
isFramebuffer() | Method | Empty |
isEnabled() | Method | Empty |
isContextLost() | Method | Empty |
isBuffer() | Method | Empty |
getVertexAttribOffset() | Method | Empty |
getVertexAttrib() | Method | Empty |
getUniform() | Method | Empty |
getTexParameter() | Method | Empty |
getSupportedExtensions() | Method | Empty |
getShaderSource() | Method | Empty |
getShaderPrecisionFormat() | Method | Empty |
getShaderInfoLog() | Method | Empty |
getRenderbufferParameter() | Method | Empty |
getProgramParameter() | Method | Empty |
getProgramInfoLog() | Method | Empty |
getParameter() | Method | Empty |
getFramebufferAttachmentParameter() | Method | Empty |
getExtension() | Method | Empty |
getError() | Method | Empty |
getContextAttributes() | Method | Empty |
getBufferParameter() | Method | Empty |
getAttachedShaders() | Method | Empty |
getActiveUniform() | Method | Empty |
getActiveAttrib() | Method | Empty |
drawArrays / drawArraysInstancedANGLE() | Method | Empty |
detachShader() | Method | Empty |
depthRange() | Method | Empty |
copyTexSubImage2D() | Method | Empty |
copyTexImage2D() | Method | Empty |
compressedTexSubImage2D() | Method | Empty |
compressedTexImage2D() | Method | Empty |
checkFramebufferStatus() | Method | Empty |
bufferSubData() | Method | Empty |
blendColor() | Method | Empty |
bindTexture() | Method | Undefined |
commit() | Method | Undefined |
finish() | Method | Undefined |
framebufferRenderbuffer() | Method | Undefined |
hint() | Method | Undefined |