恢复应用程序时 SceneKit 场景滞后
SceneKit scenes lag when resuming app
在我的应用程序中,我同时显示了几个简单的场景(一个 80 段球体,具有 500 像素 x 1000 像素的纹理,每分钟旋转一次)。当我打开应用程序时,一切都很顺利。我使用不到 50mb 的内存和大约 30% cpu 的使用率获得恒定的 120fps。
但是,如果我最小化该应用程序并在一分钟后返回它,或者只是停止与该应用程序交互一段时间,尽管 Xcode 报告,所有场景都会非常滞后并达到 4 fps 左右30fps,正常内存使用,超低 (~3%) cpu 使用。
我在真实 iPhone 7 iOS 10.3.1 上测试时遇到此行为,我不确定此行为是否存在于其他设备或模拟器上。
这是我收集来演示此问题的示例项目。 (link here) 我是不是做错了什么?我怎样才能唤醒场景并恢复使用尽可能多的 cpu 来保持良好的 fps?
我可能不会直接回答你提出的问题,但可以给你一些思考的要点。
我在我的第 6 代 iPod(64 位)iOS 10.3.1 上启动了您的演示应用程序,它从一开始就滞后了大约一分钟的 FPS 2-3。然后过了一段时间,它开始平稳地旋转。进入背景 - 前景后也是如此。可以用一些纹理缓存来解释。
我调整了其中一个 SCNView 的大小,使其适合屏幕,其他视图则留在后面。设置 v4.showsStatistics = true
这是我得到的
如您所见,Metal flush 一帧大约需要 18.3 毫秒,并且仅适用于 一个 SCNView。
据此
So, if my interpretation is correct, that would mean that "Metal
flush" measures the time the CPU spends waiting on video memory to
free up so it can push more data and request operations to the GPU.
所以我们可能怀疑问题出在同时使用 GPU 的 4 个不同的 SCNView 中。
- 让我们检查一下。与第 2 点相比,我删除了后面的 3 个 SCNView,并将这些视图中的 3 个行星放到了前面的视图中。所以一个 SCNView 一次有 4 个行星。这是截图
如您所见,Metal flush 最多需要 5 毫秒,而且从一开始就一切顺利。您可能还会注意到三角形的数量(右上角的图标)是我们在第一个屏幕截图中看到的数量的四倍。
综上所述,只需尝试将所有 SCNNodes 组合在一个 SCNView 上,可能会提高速度。
所以,我终于想出了一个部分功能性的解决方案,尽管它不是我想象的那样。
我尝试的第一件事是按照 Sander 的回答的建议将所有节点保留在一个全局场景中,并按照 中的建议将委托设置在一个 SCNView 上也许这曾经有效或者它在不同的环境中工作,但对我不起作用。
Sander 最终帮助我的是性能统计的使用,我不知道它的存在。我为我的一个场景启用了它们,一些关于性能的东西对我来说很突出:
在 运行 的前几秒,在应用出现严重的帧丢失之前,性能显示显示为 240fps。 "Why was this?",我想。谁会在具有 60hz 显示屏的移动 phone 上需要 240 fps,尤其是当 SceneKit 默认值为 60 时。然后它击中了我:60 * 4 = 240。
我猜发生的事情是单个场景中的每个更新都会触发 "metal flush",这意味着每个场景每秒被刷新 240 次。我猜这会慢慢填充 gpu 缓冲区(或内存?我不知道),最终 SceneKit 需要开始清除它,而 4 个视图中的 240 fps 实在是太多了,无法跟上。 (这解释了为什么它在完全下降之前最初会获得良好的性能。)。
我的解决方案(这就是我说 "partial solution" 的原因)是将每个 SceneView 的 preferedFramesPerSecond 设置为 15,总共 60(我也可以在 phone,但我不确定这是否适用于较弱的设备)。不幸的是,15fps 明显不稳定,但比我最初获得的糟糕表现要好得多。
也许将来 Apple 会为每个 SceneView 启用唯一刷新。
TL;DR:将所有 SceneView 的 preferredFramesPerSecond 总和设置为 60。
在我的应用程序中,我同时显示了几个简单的场景(一个 80 段球体,具有 500 像素 x 1000 像素的纹理,每分钟旋转一次)。当我打开应用程序时,一切都很顺利。我使用不到 50mb 的内存和大约 30% cpu 的使用率获得恒定的 120fps。
但是,如果我最小化该应用程序并在一分钟后返回它,或者只是停止与该应用程序交互一段时间,尽管 Xcode 报告,所有场景都会非常滞后并达到 4 fps 左右30fps,正常内存使用,超低 (~3%) cpu 使用。
我在真实 iPhone 7 iOS 10.3.1 上测试时遇到此行为,我不确定此行为是否存在于其他设备或模拟器上。 这是我收集来演示此问题的示例项目。 (link here) 我是不是做错了什么?我怎样才能唤醒场景并恢复使用尽可能多的 cpu 来保持良好的 fps?
我可能不会直接回答你提出的问题,但可以给你一些思考的要点。
我在我的第 6 代 iPod(64 位)iOS 10.3.1 上启动了您的演示应用程序,它从一开始就滞后了大约一分钟的 FPS 2-3。然后过了一段时间,它开始平稳地旋转。进入背景 - 前景后也是如此。可以用一些纹理缓存来解释。
我调整了其中一个 SCNView 的大小,使其适合屏幕,其他视图则留在后面。设置
v4.showsStatistics = true
这是我得到的
如您所见,Metal flush 一帧大约需要 18.3 毫秒,并且仅适用于 一个 SCNView。
据此
So, if my interpretation is correct, that would mean that "Metal flush" measures the time the CPU spends waiting on video memory to free up so it can push more data and request operations to the GPU.
所以我们可能怀疑问题出在同时使用 GPU 的 4 个不同的 SCNView 中。
- 让我们检查一下。与第 2 点相比,我删除了后面的 3 个 SCNView,并将这些视图中的 3 个行星放到了前面的视图中。所以一个 SCNView 一次有 4 个行星。这是截图
如您所见,Metal flush 最多需要 5 毫秒,而且从一开始就一切顺利。您可能还会注意到三角形的数量(右上角的图标)是我们在第一个屏幕截图中看到的数量的四倍。
综上所述,只需尝试将所有 SCNNodes 组合在一个 SCNView 上,可能会提高速度。
所以,我终于想出了一个部分功能性的解决方案,尽管它不是我想象的那样。
我尝试的第一件事是按照 Sander 的回答的建议将所有节点保留在一个全局场景中,并按照
Sander 最终帮助我的是性能统计的使用,我不知道它的存在。我为我的一个场景启用了它们,一些关于性能的东西对我来说很突出: 在 运行 的前几秒,在应用出现严重的帧丢失之前,性能显示显示为 240fps。 "Why was this?",我想。谁会在具有 60hz 显示屏的移动 phone 上需要 240 fps,尤其是当 SceneKit 默认值为 60 时。然后它击中了我:60 * 4 = 240。
我猜发生的事情是单个场景中的每个更新都会触发 "metal flush",这意味着每个场景每秒被刷新 240 次。我猜这会慢慢填充 gpu 缓冲区(或内存?我不知道),最终 SceneKit 需要开始清除它,而 4 个视图中的 240 fps 实在是太多了,无法跟上。 (这解释了为什么它在完全下降之前最初会获得良好的性能。)。
我的解决方案(这就是我说 "partial solution" 的原因)是将每个 SceneView 的 preferedFramesPerSecond 设置为 15,总共 60(我也可以在 phone,但我不确定这是否适用于较弱的设备)。不幸的是,15fps 明显不稳定,但比我最初获得的糟糕表现要好得多。
也许将来 Apple 会为每个 SceneView 启用唯一刷新。
TL;DR:将所有 SceneView 的 preferredFramesPerSecond 总和设置为 60。