java - 旋转 Canvas 和绘制位图性能

标签 java android bitmap rotation frame-rate

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

位图图像 = BitmapFactory.decodeResource(getResources(),R.mipmap.totone);

我还有一个存储角度的变量。然后在绘图函数中,我只是旋转 Canvas ,绘制我的星球(现在旋转),然后将 Canvas 旋转回来。像这样:

//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

最佳答案

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

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

解释

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

我们假设 onDraw() 执行大约需要 15 毫秒。还剩 1.7ms;一切安好!您将获得漂亮、流畅的 60Hz 旋转。

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

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

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

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

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

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

针对可玩性的建议修复

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

关于java - 旋转 Canvas 和绘制位图性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54840914/

相关文章:

java - Reader读取文件时缺少行

android - 如何像 iPhone 一样实现滚轮小部件?

android - 将android资源位图批量转换为不同密度的工具

java - 在构造函数或声明中初始化类字段?

java - 是否可以将 ArrayList 除以 double 并创建一个新列表?

java - 将 int 0-65535 存储在固定 16 位上并转换回来

android - 如何从索引中获取 ListView 中项目的特定 Id?

android - 如何在一键登录中使用 Google Activity Result API

android - 将 BitmapDrawable 转换为位图

android - 仅在垂直方向倾斜位图