webgl 游戏_U4 内核特性揭秘 高性能的游戏模式

招贤纳士

我们急需浏览器渲染引擎/Flutter 渲染引擎人才,欢迎大牛们加入我们

前言

随着行业的发展,越来越多的开发者在其业务中引入互动小游戏,以此去提升业务的留存率,活跃度及商业收入等。H5 小游戏基于 Web 技术构建,天然具有研发周期短,快速更新,跨平台以及生态上的优势,因此也是许多业务方优先考虑的方案。作为 Web 引擎的研发团队,如何在引擎内核层面针对 H5 游戏提供更加高效的渲染性能,同时做到兼容性最好,适配成本最低,使大部分的游戏业务场景能以较少的改造成本获得更多的性能收益,最终达到更好的用户体验。这是我们一直努力的方向。

过去,我们发表了一篇介绍游戏模式的文章,在这期间我们根据业务方同学的反馈对游戏模式进行了持续的优化,更进一步降低业务方的接入成本。本文主要介绍在基于 Web 方案的 H5 小游戏场景下,当前内核的渲染流程以及问题所在;游戏模式的优化方案以及它的优点,并配以实测性能数据说明使用该方案的效果;最后,本文还会介绍未来内核团队在互动类游戏的近期规划。欢迎业务方的同学使用,同时,我们也欢迎对 Web 引擎渲染技术感兴趣的同学一起讨论学习。

渲染流水线简析
基本流程

我们先来看下 Chromium 原生的 Canvas 渲染流水线的基本流程。下面是 Chromium Android WebView 的单进程渲染架构下,Canvas 更新一帧内容的一个简单示意图: 

73fd0205ff11a4edf835f16920a84abe.png

UI 线程在接收到系统的 VSync 信号后,通知合成器开始准备新的一帧(Frame N)的绘制内容。合成器向 Blink 发送 BeginMainFrame 的请求,通知 Blink 开始准备新的绘制内容。Blink 主线程在收到合成器的请求后,会触发 requestAnimationFrame 的回调,让 JS 开始执行对应的绘制操作,进行一帧的绘制指令的收集。需要注意的是,在 Blink 的渲染线程中,并没有进行真正的光栅化。如果是 Canvas 2D,则是通过 Skia 的 SkPicture 进行对应的绘制指令的录制;如果是 WebGL,则会把对应的 GL 指令 Encode 到 Command Buffer 的缓存中.当 JS 绘制完毕一帧之后,Blink 会将收集到绘制指令通过 Command Buffer 提交给 GPU 线程进行该帧真正的光栅化,当下一个 VSync(Frame N + 1)到来时,合成器才开始准备 Frame N 的真正绘制,将包含光栅化的结果(一般是一个 GPU 纹理)的 DrawQuad 组合成 CompositorFrame 并同步给位于 Android Render Thread 中的父合成器,父合成器再将 CompositorFrame 转换成 GL Frame 进行 GL 绘制,绘制完成后调用 SwapBuffer 最终完成这一帧的上屏。

WebView 作为 Android View 体系的成员之一,也同样需要遵循 HWUI 的渲染规则。在硬件加速模式下,WebView 最终的上屏也必须是在 Android 的 Render Thread 中,但是 WebGL 自身的内容仍然是在 Chromium 的 GPU 线程中完成光栅化的,如下图所示:

49ff479f3355dcf914a56cec67a724dc.png

在 Chromium 的 GPU 线程中,会为 WebGL 创建的单独的 Context 以及 FBO。Blink 端收集到对应的一帧绘制指令后,会通过该 FBO 将 WebGL 的内容光栅化到一块纹理上面,也就是说这一帧 WebGL 的内容在 GPU 线程完成光栅化之后其实就已经绘制出来了。但是为 WebGL 所创建是 OffScreen 的 FBO,因此仍然需要等待子合成器(Layer Compositor)将包含 WebGL 纹理的绘制信息(Compositor Frame)提交给父合成器(Parent Compositor),由父合成器(Parent Compositor)将 WebGL 对应的纹理绘制到 OnScreen 的 FBO 上面,来实现最后的上屏。需要注意的是,Android Render Thread 和 Chromium GPU 线程,两者拥有各自的 GL Context,两个 GL Context 之间需要通过 eglImage 来实现纹理共享。

问题及优化空间

通过上面的流程梳理可以了解到,在 Chromium 渲染流水线里面,Canvas 元素的内容更新跟其他 DOM 元素的内容更新一样,都需要走非合成器动画的渲染流水线。一帧完整的内容更新,需要经过 Blink 内核先产生绘制指令,再经过光栅化,最后通过两级合成器的调度,才能最终完成上屏。在 Chromium Android WebView 架构下,整个过程会跨越三个 VSync 周期,从 VSync 触发到最终上屏的整个过程相对较长。即使是在光栅化完成之后,也仍然需要经过两级合成器的调度,才能最终完成一帧的绘制,存在一些冗余的开销,也增加了 CPU 消耗以及操作延时。而两级合成器的调度,更多地的还是为合成器动画的流畅度而优化,针对整个页面的可视区域就是只有一个 Canvas 的小游戏场景来,收益并不是很大。

针对上述的问题,我们希望在内核层面,提供一种新的更加精简和高效的 Canvas 渲染流水线,减少 Overhead 以及降低 CPU 占用率和操作延时。同时,也希望对于大部分的游戏场景来说,新的渲染流水线依旧能够保持原有的 Web 标准以及调用方式,只需要非常小的适配成本即可完成两种流水线之间的切换。

我们把这种新的渲染流水线方案命名为 :Canvas 游戏模式。 下面就来具体介绍一下游戏模式的相关原理及使用方式。

游戏模式

优化方案

从上面的分析中可以看到,Chromium 本身会就创建一个 GPU 线程并且创建对应的 GL 环境,WebGL 自身的内容在 Chromium 的 GPU 线程就能独立完成一帧的光栅化处理,也就意味着WebGL对应的纹理在光栅化完成后其实就已经准备好了,但是因为其绑定的是一个 Offscreen FBO,仍然需要等待父合成器将其绘制到 OnScreen 的 FBO 上。那么,我们能否在 GPU 线程光栅化完成之后,跳过后面两级合成器的工作流程,直接绘制到一个 OnScreen 的 FBO 上完成上屏呢?因为 WebView 的 Render Target 是 Activity 默认的 Window,而 Android HWUI 的架构规定普通 View 的上屏必须是在 App RenderThread 中,WebView 也需要遵循这一规则。

因此,我们首先需要对 Render Target 作出调整以去除这个限制。如果我们需要在 Chromium 自身的 GPU 线程直接将 WebGL 对应的纹理绘制到 OnScreen FBO 时,就不能使用 Activity 默认的 Window 作为 Render Target,而是必须使用 SurfaceView 作为在游戏模式下的 Render Target,这样可以不依赖 App RenderThread,同时也可以直接省去后面两级合成器的工作。在 Chromium 自身的 GPU 线程中,处理完光栅化之后,将内容直接绘制到 SurfaceView 上,大致流程如下图所示。

0b6ea6ecb9cc1d81f720e005c98ad45a.png方案优点

注意,下文提到的 Blink 主线程,GPU 线程指的是 Chromium 单进程架构下的各个线程。如果是 Chromium 多进程架构,则对应的是 Renderer 进程下的 Blink 主线程,以及 GPU 进程。

兼容 Chromium 原生架构

优化方案没有修改 Blink 主线程与 GPU 线程之间通过 Command Buffer 提交指令的流程,因此可以无缝兼容 Chromium 现有的多进程架构设计以及原生的渲染流水线。

更好的性能

从渲染流水线的角度看,游戏模式下渲染流水线就变成了两段式的架构,Blink 主线程负责记录及收集绘制指令,GPU 线程负责将进行光栅化,并直接绘制到一个 SurfaceView 上面。该方案与一些 Native 实现的游戏渲染引擎比较类似,理论上可以极大的精简 Canvas 的渲染流水线,减少 Overhead 及操作延时。

页端适配成本低

WebGL/Canvas 2D 的接口及语义完全保持不变,对页面的兼容性不会有任何影响。同时,开启游戏模式的方式也极其简单,只需要在获取 Context 时设置一个开关即可启用游戏模式。代码用例如下所示,在调用 getContext 时新增一个 gameMode 的选项:

gl=canvas.getContext("webgl", {gameMode:true});
因此,对于现有的游戏业务来说,适配成本非常低,只需要做一行代码的适配即可集成;对于现有的游戏引擎(如 Cocos、白鹭等)来说,在不需要修改引擎内部流程及机制的前提下,做到完全无缝兼容。优化效果
实验室测试数据

通过实验室的压测对比,相比较标准模式(Chromium 原生渲染方式),游戏模式在帧率上有超过 10% 的提升。另外,因为渲染流水线变得更短,所以帧延时也会更低,不再需要像标准模式一样,跨越多个 VSync 周期才能完成一帧的上屏。测试结果如下图所示:

6df3573673f024352961a62da07862e6.png

在 CPU 占用率方面,相比标准模式能够降低 30% 以上,这对于游戏场景来说,可以带来更好的耗电及散热表现。测试结果如下图所示:

413cda3981ef94fe23b2c1f11f81e5fe.png

目前,UC 浏览器的小游戏平台也已经接入游戏模式并正式上线。我们针对几款代表性的游戏,测试了 CPU 占用率。从测试结果上看,4 款游戏在游戏模式下,CPU 占用率分别降低了 15%-33%。测试结果如下图所示:

5876f67be4b78e9dcf03cec525110ef6.png

通过上面的几组对比数据可以看到,H5 游戏使用了游戏模式后,对于 CPU 占用和帧率均有较明显的性能收益。

未来规划
  1. 指令传输优化。目前的方案需要通过 Chromium 的 Command Buffer 机制,来实现 Blink 主线程与 GPU 线程之间绘制指令的传递。因此 Command Buffer 本身的 Decode/Encode 性能对帧率的影响会比较关键。如何进一步优化 Command Buffer 的性能,降低这部分的所产生开销,是我们后面进一步优化的重点。

  2. 渲染交互异常监控。针对一些游戏业务在运行过程中出现黑屏、卡顿现象,在内核层面实现统一的黑屏检测,卡顿检测机制,形成黑屏率,卡顿率等关键指标供业务方来作为衡量游戏运行状态的一种手段和参考,辅助业务方更加有效的提升游戏的体验。

结语

至此,你已经了什么是 U4 内核的游戏模式,它的用法、收益以及实现细节。如果你的 H5 游戏业务已经运行在 U4 内核,欢迎试用我们的游戏模式;如果你想了解我们的新技术,希望本文能给你带来一定帮助。


U4内核致力于打造性能最好、最安全的web平台,让web无所不能。

关注请长按二维码

喜欢请分享到朋友圈

8f484d0641bf3a6e71b2f06eebff9a99.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值