微信小游戏 - 运行时分析

HamletKent 发布于3月前 阅读171次
0 条评论

这是个人关于微信小游戏系列文章的第二篇,在这系列文章里会描述 ——

  • 如何把一些 Canvas/WebGL Demo 移植到小游戏环境并支持双端运行;
  • 对小游戏在 Android 平台的运行时架构进行分析;
  • 通过对移植的 Canvas/WebGL Demo 在小游戏和 Chrome for Android 浏览器上做 Benchmarking,对 H5 游戏 vs 小游戏的渲染性能进行对比和分析;

本文对运行时的分析只针对 Android 平台,并不包括 iOS 平台。另外小游戏实现代码并没有开源,以下分析都是使用 Profile 工具进行外部分析加上部分猜测的结果,不保证完全正确。

窗口结构

微信小游戏 - 运行时分析

小游戏包含了两个全屏的窗口,一个是 Activity 的主窗口,用于绘制 Canvas 之外的其它 UI 元素,比如上图右上角的菜单按钮,右下角的 vConsole 按钮,左上角的 FPS 标签;另外一个是 GLSurfaceView,嵌入到 Activity 的 View Hierachy 里面,用于 Canvas 的绘制。

这是典型的 SurfaceView 的用法,位于主窗口之下,View Hierarchy 的绘制在碰到 SurfaceView 的时候会 Clear 主窗口的相应区域,让位于下方的由 SurfaceView 创建的 Window 可以透出来。这样 View Hierarchy 中位于 SurfaceView 之上的其它 View 看起来就像是悬浮在上面。

type   |       frame         | name 
-----------+---------------------+------
       HWC | 0,    0, 1440, 2560 | SurfaceView - com.tencent.mm/com.tencent.mm.plugin.appbrand.ui.AppBrandUI
       HWC | 0,    0, 1440, 2560 | com.tencent.mm/com.tencent.mm.plugin.appbrand.ui.AppBrandUI

运行 “adb shell dumpsys SurfaceFlinger” 可以看到当前参与合成的窗口:

  1. 一个是 Activity 的主窗口 - “AppBrandUI” ;
  2. 另外一个是作为子窗口的 SurfaceView - “SurfaceView”;

运行线程

小游戏运行的线程架构很简单,基本上可以认为是单线程的架构,一个独立线程负责运行 v8 虚拟机,执行 JavaScript 代码,并调用相应的 GL 指令对 GLSurfaceView 进行绘制。GLSurfaceView 所分配的子窗口自己独自更新,跟 Activity 主窗口的合成由 Android 系统的窗口合成器 SurfaceFlinger 来负责。

如果考虑事件处理,会多涉及一个线程,主线程 —— UI 线程接受到事件后发送到小游戏的运行线程,再转换成相应的数据结构传递给 v8 虚拟机去调用注册的事件处理器。

总的来说,这样的窗口结构和线程架构简单而高效,Android 平台上大部分手游多半也是采用相似的架构。

渲染分析

首先小游戏不会为主 Canvas 分配额外的 Buffer,主 Canvas 是直接绘制在 GLSurfaceView 所分配的窗口上,造成的结果是:

  1. 小游戏环境里面只能有一个可以直接显示的 Canvas;
  2. 无论这个 Canvas 在代码里面设置的大小如何,它实际的渲染分辨率都是 GLSurfaceView 的窗口分辨率,也就是运行设备的屏幕分辨率,如果两者长宽比例不一致,可能会出现画面变形的结果;

所以在小游戏里面主 Canvas 的长宽比例最好跟通过 JavaScript 获取的 window 的长宽比例保存一致,另外小游戏主 Canvas 的默认长宽就是 window 的虚拟像素大小。

这种做法单纯从性能的角度来说有好有坏,后面我们在做性能分析的时候再来细述。

对 WebGL 来说,小游戏的实现应该很简单,每个 WebGL API 调用就是直接调用相应的 GL 指令,并没有使用 CommandBuffer 之类的指令缓存,在单线程架构下使用 CommandBuffer 也毫无意义。

2D Canvas 的实现,因为需要将 2D 绘图指令转换成 GL 指令,中间可能有较多的 CPU 开销,使用指令缓存不但可以通过批量发送 GL 指令给 GPU 来提高效率,而且也可以做绘图指令的合并优化,将多个 2D 绘图指令合并成一个 GL 指令,比如同样的 Bitmap 或者 Shape 连续在多个位置重复进行绘制。小游戏可能使用了一个固定大小的 2D 绘图指令缓冲区,当缓冲区满了就批量处理一次,或者也可能是固定指令数量。

查看原文: 微信小游戏 - 运行时分析

  • silversnake
  • blackswan
  • smallladybug
  • smallfrog
  • crazypeacock
  • organicladybug
  • crazyduck
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。