GCanvas 渲染引擎介绍

GCanvas 渲染引擎介绍

GCanvas 已经正式开源,开源官方主页,传送门

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 实现的差异,网络图片下载,字体渲染等方面。

核心渲染库
核心渲染库包括对外统一的接口,以及 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
42
43
44
45
46
47
48
49
<template>
<div>
<gcanvas v-if="isWeex" ref="canvas_holder" style="top: 0; width:750;height:1000;position:absolute;"></gcanvas>
<canvas v-if="!isWeex" ref="canvas_holder" style="width:750px;height:1000px;"></canvas>
</div>
</template>
<script>

const isWeex = weex.config.env.platform !== 'Web'
const { enable, WeexBridge, Image: GImage } = require('gcanvas.js');
const EnvImage = !isWeex ? Image : GImage;

export default {
data() {
return {
isWeex: isWeex ? 1 : 0
}
},
mounted: function () {
let ref = this.$refs.canvas_holder;
if (isWeex) {
ref = enable(ref, {bridge: WeexBridge});
}

var ctx = ref.getContext('2d');

//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 EnvImage();
image.onload = function(){
ctx.drawImage(image, 100, 330);
ctx.drawImage(image, 100+300, 330, 225, 75);
}
image.src = 'https://gw.alicdn.com/tfs/TB1KwRTlh6I8KJjy0FgXXXXzVXa-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 和 WebGL API 的支持列表,支持常用的接口。API 覆盖情况请参考官网内容。
详见官网链接: Context2D 和 WebGL

题图:https://unsplash.com/photos/y3KZwM_nBTQ By @Trevor Paterson

.article-entry ol, .article-entry ul { list-style-position: outside; }

文章来源:

Author:Taobao FED
link:http://taobaofed.org/blog/2017/07/27/gcanvas/