在写着架构博文的时候,突然想测试一下动画效果。于是直接就上了 bp.startAnimation()
,突然发现帧率才25左右。哦天哪,这效率可比 Pixi 差了不是一点半点。于是返回 GLantern 查看,果然是 GLantern 的问题。大致定位之后就得修补啊……
一开始,我还以为是数组的太大导致的效率低下。此时帧率大概25。
于是我做了一下 CPU 探查,并查看时间线。(抱歉这二者没截图。)
结果是脚本执行时间占大头,在70%左右,同时 CPU 总计占用排名第一的用户函数是 bufferData()
(也就是 WebGLRenderingContext.bufferData()
)。凭这个,我认为是数据量太大导致每次绘制时传输数据缓慢。于是我粗略估算了一下,第一大 PackedArrayBuffer
(属于一个颜色数组)的项数量在14万多一点点。才14万,这个数据量还是挺小的。
我做了一个实验,注释或短路掉特定的操作,查看此时的绘制情况。让我惊奇的是,问题源头明显是 RenderHelper.renderPrimitives()
和 RenderHelper.renderBuffered()
(因为只有它们调用了 PackedArrayBuffer.syncBuffer()
,内部调用 WebGLRenderingContext.bufferData()
),但是在将它们的绘制调用(glc.drawElements()
)注释掉之后,即使保留其他语句,帧率都能达到60。
此时的时间线是这样的:
这直接推翻了我“大数据量”的假设,让我更迷惑了:看似完美的绘制逻辑中,哪里出了问题呢?
我想着,先把能优化的优化一下吧。所以我写了一个小小的优化,默认缓存了 Graphics
的内容(原先每一帧都要所有的 IGraphisDataRenderer
重新绘制)。优化前后有什么不同呢?优化前,每一帧都有几次 RenderHelper.renderPrimitives()
调用和几次 RenderHelper.renderBuffered()
调用,优化后只剩下了后者。
这次的绘制帧率不到30,比之前略强了一点:
但是时间线的数据和做这个优化之前(注意不是上面第二张图,而是忘记截了的原状态下的时间线)的大相径庭:
查看其时间线可以发现,在后面花了很多时间在非用户脚本优化上,而脚本比例小了很多。也就是说,虽然 drawElements()
调用时间不长,但是 执行处理时间长。这和很久之前的症状是一样的,让我开始怀疑是否是绘制步骤错误或者参数错误。而且,问题一定是出在 RenderHelper.renderBuffered()
中的某个地方。
CPU 探查和堆快照结果如下:
可以看到,最大的数组就是 1 MB 多一点。还是一头雾水。我将目标大致放在了 bufferData()
前后。这样的话真凶是使用模式吗?(使用模式影响 OpenGL 对数据的缓存策略。)
一般的例子中用的都是 gl.STATIC_DRAW
,意义为写一次频繁用,我蛋疼地试着将它改成了 gl.DYNAMIC_DRAW
,意义为频繁写频繁用。令我吃惊的是,帧率马上就上去了:
CPU 探查结果虽然不是很令人满意,却有了不少的提升:
其他倒是没怎么变化:
这么说真凶就是使用模式啦。(其实我并不是很明白为什么——因为实际上传过去的数据是几乎不变的。)
堆内存分配那边我看过,并没有内存泄露。
再做一个实验,在改为 gl.DYNAMIC_DRAW
的情况下,如果 Graphics
不默认缓存为位图(贴图)的话,帧率从48下降到42左右。
47 FPS,这个值还是低于 Pixi 的稳定60,而且处理时间还是很长,有没有其他的问题呢?我想到了循环——手工循环(JavaScript)和自动循环(shader),因此转而怀疑起滤镜的应用来。
我目前没有实现自动调整大小的 RenderTarget2D
,所以滤镜 shader 每次都应用(对于目前帧大小)1024×512、(5+5)×2+3次,加上其他开销(每个 DisplayObject
有至少两次,一次原始绘制加上至少一次作为孩子被拷贝,一共至少7×2次),量很大。
于是,在 gl.DYNAMIC_DRAW
条件下,将 BlurShader
和 Blur2Shader
的循环次数改成3+3,在 Graphics
不缓存时平均帧率能达到54,不过边线就更明显了:
缓存时能维持在60:
如果设置为2+2,能轻松达到平均帧率60,不过线条更明显了;设置为1+1就没法看了。
在 gl.STATIC_DRAW
条件下,缓存时设置为3+3帧率稳定在38左右。可以看到,使用模式不同对效率造成了很大的影响。
关于效果,即使是3+3有边线,窃以为效果还是比 Pixi 的极速shader好的。
综合所有的因素,最后就选择了 gl.DYNAMIC_DRAW
、3+3并缓存 Graphics
内容。
X+X 的意义见这里。
今天解决了 Visual Studio 2015 的 Web 项目相关的缺失、损坏等问题(就是造成之前 TypeScript 项目属性无法查看的那个)。这个问题还导致我在安装 Web Essentials 时报错说缺少依赖项 Web Developer Tools,在 VS 的安装程序中修改(添加、删除)“Web 开发人员工具”项(也就是 Web Developer Tools)时显示安装成功却实际上没变化(错误依旧)。
一楼的方案是可用的,修复 Microsoft ASP.NET 5 RC1 即可。