【问题标题】:Canvas performance change in ChromeChrome 中的画布性能变化
【发布时间】:2013-09-14 11:52:37
【问题描述】:

我正在开发一个动画库,并且每隔一段时间我都会运行一次基准测试,看看我在使用某些功能时获得了多少收益或损失。最近遇到一件让我很困惑的事情,也许有更多知识的人可以为我解释一下。

之前的表现:

  • Chrome:~4460 个精灵 @ 30fps
  • Safari:~2817 个精灵 @ 30fps
  • FireFox:~1273 个精灵 @ 30fps
  • iPhone 4S:~450 @ 30fps

现在的表现:

  • Chrome:~3000 个精灵 @ 30fps
  • Safari:~2950 个精灵 @ 30fps
  • FireFox:约 1900 个精灵 @ 30fps(在垃圾收集变得过于分散注意力之前)
  • iPhone 4S:~635 @ 30fps

因此,您可以看到,Chrome 的性能受到了相当大的打击,而其他所有浏览器似乎在这段时间内都变得更好了。我注意到的最重要的事情,我想的是答案,是 Chrome 中的 CPU 使用率似乎已经被限制了(我发誓在我能接近 90% 之前,现在它的最大值约为 60%)。大部分 CPU 都用于drawImage() 调用,我不确定我能做些什么来优化它。

如果这只是 Chrome 现在限制我的 CPU 使用率的问题,我可以接受。

任何见解将不胜感激......

_s.Sprite.prototype.drawBasic = function() {
    var s = this.ctx;
    if(s.globalAlpha!=this._alpha) s.globalAlpha = this._alpha;

    var width = this.width;
    var height = this.height;
    var x = this._x;
    var y = this._y;

    if (_s.snapToPixel) {
        x = this._x + (this._x < 0 ? -1 : 0) | 0;
        y = this._y + (this._y < 0 ? -1 : 0) | 0;
        height = height + (height < 0 ? -1 : 0) | 0;
        height = height + (height < 0 ? -1 : 0) | 0;
    }


    var frame = this.sequence[this.frame] || 0;
    var sheetY = frame + (frame < 0 ? -1 : 0) | 0;
    var sheetX = (frame - sheetY) * this.spriteSheetX || 0;

    s.drawImage(this.bitmap.image, this.bitmap.frameRect.x2 * sheetX, this.bitmap.frameRect.y2 * sheetY, this.bitmap.frameRect.x2, this.bitmap.frameRect.y2, x - (width * this._scaleX) * this.anchorX, y - (height * this._scaleX) * this.anchorY, width * this._scaleX, height * this._scaleY);
    this.updateFrame();

};

更新

所以我下载了旧版本的 Chrome (25.0.1364.5),并运行了我的基准测试:

然后我在最新版本的 Chrome 中重新运行:

显然 Chrome 已经改变了。是故意的吗?我不知道。您可以看到,在旧版本的 Chrome 中,我实际上比原来的 4460 获得了更多的性能(+ ~400,我的优化肯定奏效了),但您也可以看到它让我悬停在 100% 的 cpu 使用率。 2x cpu 几乎是屏幕上的 2x 对象。

【问题讨论】:

  • 这个不看相关代码就很难回答了。
  • 1) 如果您正在搜索表演,请将图像放在画布中以获得 33% 的提升。 2) 屏幕坐标将始终 >=0,因此无需测试符号。如果坐标
  • 我猜人们错过了我的问题......我不是想通过这个问题获得表现,我有各种各样的技巧。我不知道的是 Chrome 是如何改变其行为以最终将自身限制在 30fps 的。我只包含代码,因为人们一直在要求它。没有我的任何代码的示例...goodboydigital.com/pixijs/canvas/bunnymark 如果您在 Chrome 中运行它...您将看到它从 ~60fps 直接跳到 30fps 的点。这不是 Chrome 过去的行为方式。
  • “我有各种各样的技巧”。然而,你错过了一些重要的。
  • @GameAlchemist 哈,是的,你的权利。我之所以这么说是因为,这些年来,我做了很多这些优化,并且看到了浏览器之间的巨大差异,甚至版本号之间的差异,就像这个问题一样。如果该标志打开,您会看到_s.snapToPixel 实际上会舍入所有内容。在旧版本的 Safari 中,这曾经是一个巨大的改进,几乎是 2 倍,但现在我看到的收益非常小。我不是故意抹黑你的意见。实际上,我已经陷入了过度优化的陷阱,以至于我最终决定选择显而易见的那些,其余的 jsPerf 来寻找最佳折衷方案。

标签: javascript performance google-chrome html5-canvas


【解决方案1】:

更新

setInterval 没有问题。只发生在requestAnimationFrame 上。这终于很有意义了。 requestAnimationFrame 已经将速度限制为 60fps,我不知道,并且似乎找不到任何关于 Chrome(其他?)将其限制为 30 (60/2) 和 20 (60/3) 的信息) 并且可能是 15(60/4)... 这使它与 60hz 保持同步,因此您永远不会以 40fps 结束,这看起来很奇怪,因为它与您的屏幕刷新率不同步。

这解释了很多。我真的很享受这为我们提供的 CPU 节省。

更新

没有我的任何代码的示例...http://www.goodboydigital.com/pixijs/canvas/bunnymark/ 如果您在 Chrome 中运行它...当它从 ~60fps 直接跳到 30fps 时,您会看到这一点。您可以继续添加更多兔子,pixy 可以处理它...... Chrome 正在限制 fps。这不是 Chrome 过去的行为方式。


所以我弄清楚这里发生了什么。并不是说性能发生了变化,我仍然可以以 30fps 的速度在屏幕上显示 4800 个对象。改变的似乎是 Chrome 尝试优化最终用户体验的方式。它实际上将速度从 60fps 降低到 ~30fps(根据开发工具为 29.9fps),这导致 if(fps&gt;=30) 返回 false:

    stage.onEnterFrame=function(fps){  // fps = the current system fps
        if(fps>=30){  // add astroids until we are less than 30fps
            stage.addChild(new Asteroid());
        }
    }

由于某种原因,大约 2800 个对象,Chrome 将速度降低到 30fps,而不是尝试尽可能快地运行……因此,如果我以 4800 个对象开始基准测试,它会保持在非常一致的 29.9fps。

(您可以在这里看到它的 60fps 或 29.9fps 两者之间没有真正的区别,唯一改变的是它切换的频率)

这是用于舞台计时的代码...

_s.Stage.prototype.updateFPS = function() {
    var then = this.ctx.then;
    var now = this.ctx.now = Date.now();
    var delta = now - then;
    this.ctx.then = now;
    this.ctx.frameRatio = 60 / (1000 / delta);
};

希望这可以帮助其他人。

【讨论】:

  • 老兄,你不应该将游戏动作和动画锁定为 fps,而是锁定时间。锁定到 fps 将为您提供可变速度。不好!
  • @Mike-O...这是一个基准...它要做的就是添加尽可能多的小行星,直到达到 30fps。我已经在我的计时代码中添加了,所以你会看到整个系统是独立于帧速率的。但是,您仍然可以通过查看now and then 之间的差异来了解 FPS...做一些数学运算,您就有了 FPS。
  • Chrome fps 仪表 - 奇怪的是 - 是性能杀手,因此是 fps 杀手。 60 到 30 仅意味着在 60Hz 显示器上丢失一帧。你没有提到你是使用 requestAnimationFrame 还是 setInterval 基于渲染。
  • 我使用requestAnimationFrame,这让我认为 Chrome 正在节流……运行时间更长……它似乎旨在实现一致性而不是性能。 60fps-30fps-20fps...
  • 很好地调用 requestAnimationFrame 呼叫...将其更改为 setInterval 并且节流消失了。我不会停止使用requestAnimationFrame,但很高兴知道。
猜你喜欢
  • 2011-04-29
  • 2016-06-26
  • 2014-03-19
  • 1970-01-01
  • 2011-12-21
  • 2015-01-28
  • 2021-10-02
  • 1970-01-01
  • 2019-04-03
相关资源
最近更新 更多