【问题标题】:Rotating canvas and drawing bitmap performance旋转画布和绘制位图性能
【发布时间】:2019-02-23 11:06:05
【问题描述】:

我正在尝试制作一个游戏,其中行星将位于用户屏幕的中心并且像行星一样非常缓慢地旋转。所以首先我决定测试它是否一切正常,但它没有......我得到一个像这样的简单“行星”图像:

Bitmap image = BitmapFactory.decodeResource(getResources(),R.mipmap.totone);

我还有一个存储角度的变量。然后在绘图功能中,我只需旋转画布,绘制我的星球(现在已旋转),然后将画布旋转回来。像这样:

//the planet's image is 512x512px
canvas.rotate(ang,256,256); //256, 256 is the center of rotation
canvas.drawBitmap(image, 0,0, null);
canvas.rotate(-ang,256,256); //rotate back

我不知道为什么,但看起来当图像旋转 90 度和 270 度时,游戏 fps 会变慢一点?我做了一个小 gif 来展示这个问题。 fps 一直是 60,但是它会无缘无故地下降到 50ish 几毫秒?这是什么原因造成的?我尝试将线程的目标 fps 更改为 30,然后看起来没有发生 fps 下降。所以这可能是性能问题。请注意,我尝试使用任何不同的方法旋转位图,fps 下降效果仍然相同..

Gif

【问题讨论】:

  • 试过canvas.concat(matrix) 后跟canvas.drawBitmap(image, 0, 0, null)?或直接:canvas.drawBitmap(image, matrix, null)?
  • @pskink 是的,可悲的是同样的事情:/

标签: java android bitmap rotation frame-rate


【解决方案1】:

这很可能是设备的固定屏幕刷新率与以特定角度绘制位图所需时间的微小变化之间的相互作用。

我猜你会在onDraw() 中将ang 增加一个常数。这个事实可以用来解释旋转速度的急剧变化。

解释

您的设备会以 60Hz 的频率刷新屏幕。这意味着onDraw() 在理想条件下以最大 60Hz 的频率被调用:大约每 16.7 毫秒一次。

假设onDraw() 需要大约15ms 的时间来执行。还剩 1.7 毫秒;一切安好!你会得到一个漂亮、平滑的 60Hz 旋转。

然后假设,在ang 的某些值下,onDraw() 只需要一点时间;说,18毫秒。 (我会推测一下为什么drawBitmap()的执行时间会根据角度而变化。现在,让我们看看这18ms的绘制时间会发生什么。)

理想情况下,onDraw() 以 60Hz 的频率被调用。但是现在你花的时间太长了;超过 1 个周期。 compositor 现在必须从您的应用程序中删除一个框架,因为您无法足够快地提供它!所以,onDraw() 不是每 16.7ms 执行一次,现在只能每 33.4ms 调用一次。

换句话说,屏幕硬件以恒定速率刷新,当您的onDraw() 超过 16.7 毫秒阈值时,您的更新速率正好减半。

这在您的 GIF 中有所暗示。显示的帧速率从 60 变为 51,但对我来说似乎很清楚实际旋转速率几乎正好下降了 50%。我怀疑这种差异仅仅是由于您计算显示帧速率的方式造成的。

对 drawBitmap() 执行时间变化的推测

可能是处理器的缓存性能。在某些旋转角度,图形逻辑可能会以不适合 L1 高速缓存/预提取逻辑的方式访问位图内存。换句话说,您可能会在这些角度遇到很多缓存未命中。

建议的可玩性修复

  1. 使用更快的图形管道,例如 OpenGL,和/或:
  2. ang 以时间破解 (uptimeMillis()) 为基础,而不是增量。您仍然会丢帧,但会更正明显的旋转速率。
  3. 如果您想真正疯狂,您可以提供第二个位图,将第一个预旋转 90 度,然后使用此位图以接近 90/270 度的角度进行绘制。如果我对缓存未命中的看法是正确的,这将改善问题。

【讨论】:

  • @Paper 嗯?不?没有骰子?
猜你喜欢
  • 2015-11-03
  • 1970-01-01
  • 2021-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
  • 1970-01-01
相关资源
最近更新 更多