【问题标题】:SceneKit scenes lag when resuming app恢复应用程序时 SceneKit 场景滞后
【发布时间】:2017-09-14 15:17:13
【问题描述】:

在我的应用程序中,我有几个简单的场景(一个 80 段的球体,具有 500 像素 x 1000 像素的纹理,每分钟旋转一次)同时显示。当我打开应用程序时,一切都很顺利。我得到恒定的 120fps,内存使用量少于 50mb,cpu 使用量约为 30%。

但是,如果我最小化应用程序并在一分钟后返回它,或者只是停止与应用程序交互一段时间,那么尽管 Xcode 报告 30fps,正常的内存使用,场景都非常滞后并达到 4 fps 左右,和超低 (~3%) 的 CPU 使用率。

在真正的 iPhone 7 iOS 10.3.1 上进行测试时,我得到了这种行为,我不确定其他设备或模拟器上是否存在这种行为。 这是我为演示此问题而收集的示例项目。 (link here)我在这里做错了吗?如何让场景唤醒并恢复使用尽可能多的 cpu 以保持良好的 fps?

【问题讨论】:

  • 我现在已经确认 iPhone SE 上的 iOS 10.2 上不会出现这个问题。

标签: ios performance graphics scenekit metal


【解决方案1】:

我可能不会直接回答你提出的问题,但可以给你一些思考的要点。

  1. 我在我的 iPod 第 6 代(64 位)iOS 10.3.1 上启动了你的演示应用程序,它从一开始就滞后到 FPS 2-3 大约一分钟。然后过了一段时间,它开始平稳地旋转。进入背景 - 前景后也是如此。可以用一些纹理缓存来解释。

  2. 我调整了其中一个 SCNView 的大小,使其适合屏幕,其他视图留在后面。设置v4.showsStatistics = true 这就是我得到的

如您所见,金属冲洗一帧大约需要 18.3 毫秒,并且仅适用于 一个 SCNView。 据此answer on Stackoverflow

所以,如果我的解释是正确的,那就意味着“金属 flush" 测量 CPU 等待显存的时间 释放,以便它可以向 GPU 推送更多数据和请求操作。

所以我们可能怀疑问题出在 4 个不同的 SCNViews 同时使用 GPU。

  1. 让我们检查一下。与第二点相比,我删除了后面的 3 个 SCNView,并将这些视图中的 3 个行星放在前面。所以一个 SCNView 一次有 4 个行星。这是屏幕截图

正如您所见,Metal flush 最多需要 5 毫秒,并且从一开始就一切顺利。此外,您可能会注意到三角形(右上角的图标)的数量是我们在第一个屏幕截图中看到的数量的四倍。

总而言之,尝试将所有 SCNNode 组合到一个 SCNView 上,可能会加快速度。

【讨论】:

  • 虽然这个答案很深入,但不幸的是,我确实需要多个 SCNView:我正在显示的内容是 UITableView 中的单元格。如果我维护一个单一的全局场景对象并将所有行星作为节点添加到不同位置的各个相机中,并且在每个 SCNview 中从场景中的不同相机显示,这会比维护许多场景提高性能吗?我想这一切都归结为 Metal 如何处理刷新场景:是每个相机一次还是每个场景对象一次。
  • @Timestretch 不幸的是,我不认为有一个 SCNView 以防万一你必须显示几个 UITableViewCells 是合适的。可能您可以通过减小图像的大小来降低性能开销。另一种方法虽然相当耗费资源,但制作一个 SCNView 并在使用需要的此类设计中制作,例如类似于 UITableView 的东西。我记得 Apple 只使用 SCNKit 制作了关于 Scene Kit 的整个 WWDC 演示文稿。
  • 奖励您赏金,因为我相当确定您的回答使我找到了正确的解决方案。希望我能在几天内得到答复
  • @Timestretch 很高兴听到这个消息。但是,听到您选择的方式以及它在性能方面的表现如何,将会很有趣。
  • 是的,我打算发布它!
【解决方案2】:

所以,我终于想出了一个部分功能的解决方案,尽管它不是我想的那样。

我尝试的第一件事是按照 Sander 的回答将所有节点保留在一个全局场景中,并按照 the second answer to this question. 中的建议将代理设置在其中一个 SCNViews 上也许这曾经有效或者它在不同的环境中有效上下文,但它对我不起作用。

Sander 最终对我的帮助是使用了我不知道存在的性能统计信息。我为我的一个场景启用了它们,性能方面对我来说很突出: 在运行的最初几秒钟内,在应用程序出现显着丢帧之前,性能显示为 240fps。 “为什么会这样?”,我想。在具有 60hz 显示屏的手机上,谁需要 240 fps,尤其是当 SceneKit 默认为 60 时。然后它击中了我:60 * 4 = 240。

我猜发生的是,单个场景中的每次更新都会触发“金属刷新”,这意味着每个场景每秒被刷新 240 次。我猜想这会慢慢填充 gpu 缓冲区(或内存?我不知道),最终 SceneKit 需要开始清除它,而 4 个视图的 240 fps 实在是太多了,无法跟上。 (这解释了为什么它最初会在完全下降之前获得良好的性能。)。

我的解决方案(这就是我说“部分解决方案”的原因)是将每个 SceneView 的 preferedFramesPerSecond 设置为 15,总共 60 个(我也可以在手机上使用 30 个,但我不确定这是否适用于较弱的设备)。不幸的是,15fps 明显不稳定,但比我最初获得的糟糕性能要好得多。

也许在未来 Apple 将启用每个 SceneView 的独特刷新。

TL;DR:在所有 SceneView 中将 preferredFramesPerSecond 的总和设置为 60。

【讨论】:

  • 此外,我解决表格视图中无限数量场景的方法是将不可见的单元格的 prefferedFramesPerSecond 设置为 0,当它们可见时设置为 15。
猜你喜欢
  • 2019-03-20
  • 2016-07-09
  • 2015-06-12
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
  • 2016-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多