【问题标题】:Major iOS9 performance issues with Sprite KitSprite Kit 的主要 iOS9 性能问题
【发布时间】:2015-10-09 16:44:02
【问题描述】:

我在使用 iOS9 时遇到了巨大的性能问题,我不知道该怎么办。我读过很多帖子——例如herehere,但他们建议的解决方案没有帮助或没有什么不同。

我的游戏已从旧 iPad 2 (iOS 8.4) 上的 60fps 下降到新 iPad mini (iOS 9) 上的

我正在努力找出罪魁祸首。我很确定其中之一是 SKCropNodes。我通常在我的场景中渲染几个 SKCropNodes (6 - 18)。这在 iOS8 中从来都不是问题,但似乎 iOS9 虽然在裁剪方面做得更好,但这样做也会消耗性能。

如果我将裁剪节点渲染为普通的 SKSpriteNodes,我在旧设备上可能会获得 5fps,而在较新的 iPhone 6 上最多可以达到 30 帧。我别无选择,只能使用裁剪节点,但这不是问题的全部。

我认为可能使用了错误的纹理图集 - 即更大的分辨率之一。然而,强迫我的设备使用一个非常小的图集并没有什么不同。

我正在使用 Texture Packer 为不同设备生成带有缩放变体的图集。我注意到 XCAssets 现在具有添加 Sprite Atlas 的选项(我似乎找不到任何关于此的文档)。这不适合我的游戏,因为我使用了 100 多个精灵。我尝试将我的地图集添加到 XCAssets,但由于某种原因,它不会使用缩放变体。尽管如此,对于低分辨率纹理,它仍然运行得非常糟糕。

我试过设置

skView.ignoresSiblingOrder = YES;

并给了我所有的节点 zPosition 值,但仍然没有效果。我还为每个图像名称添加了 .png 扩展名(最初是一个意味着它们不会呈现的问题。)

我的场景中有一些 SKEffectNode,但删除和添加这些似乎没有效果。

我不明白相同的硬件和相同的代码如何产生如此截然不同的结果。显然,Apple 已经改变了一些与渲染有关的东西,这已经产生了不利影响。他们似乎也无意解决这些问题。我知道这个问题上的错误已经存在了几个月——早在 iOS9 发布之前。

我已经在这个游戏上工作了 2 年了,只是在 iOS9 之前才发布它。它现在正遭受糟糕的性能和经常崩溃的困扰。

有没有人弄清楚 Apple 究竟做了什么来扼杀性能?如果我知道这一点,我至少可以尝试解决它......谢谢。

更新

以下是同一场景的一些数据,其中包含游戏一次生成的绝对最大节点数。

iOS 8、iPad 2、~200 个节点、~100 次绘制、58.7 - 60 fps

iOS 9,iPhone6,~280 个节点,~216 次绘制,大约 20 fps

我认为节点数量的差异是由于屏幕尺寸不同。如果我在 iPhone 6 上更改场景以达到等效值,FPS 仍然在 24 左右。

更新 2

使用 Xcode 的模板 Sprite Kit 项目,并将宇宙飞船更改为包含宇宙飞船的 SKCropNode,在 iOS 8 上,我能够添加 100 艘没有帧速率问题的飞船。在 iOS 9 上,同样的项目,我可以在帧速率下降到

iPad2 上的 iOS 8:

iOS 9 iPhone 5:

就纹理图集的使​​用而言,正如我的评论中所说,我不能保证任何东西都来自同一个图集。我的游戏包含自定义角色,以及来自一系列图集的资产(每个图集包含约 100 个纹理)。屏幕上一次最多可以有 9 个字符。我知道这在平局方面不是最有效的,但直到 iOS9 之前我从来没有遇到过问题......

更新 3

我已向 Apple 提交了一个错误,包括我的示例程序。我还用完了我的一项技术支持请求。到目前为止,苹果没有任何消息。

【问题讨论】:

  • 请使用相关性能信息更新您的问题,例如:8 vs 9 上的绘制调用次数和 FPS、8 vs 9 的仪器时间和 fps 配置文件等。
  • 好的,我添加了更多信息。即使在同一场景中的 iPhone 6 与 iPad 2 上,性能也会受到巨大影响。
  • @Smikey 关于抽奖次数(与双抽问题无关)对于 200 个节点来说,即使 100 次抽奖也太多了。 .首先确保您正确使用地图集。阅读此内容以了解有关什么会破坏批处理过程的更多信息:stackoverflow.com/a/22856964/3402095。其次,您必须记住,SKLabelNode、SKShapeNode 和 SKCropNode 需要(至少)每个节点一个绘制调用。那些不能像SKSpriteNode那样批量绘制。
  • @Smikey 我很好奇。你提供的两张照片你得到了什么抽奖电话?你应该只得到一些。如果您已经为这两张照片提供了该信息,很抱歉没有看到它。还有那些来自实际设备的屏幕截图?
  • @Smikey 您能否链接到您正在展示并提交给 Apple 的测试项目的下载?

标签: objective-c performance sprite-kit ios9 xcode7


【解决方案1】:

有两个主要问题。

其中一个原因是从 iOS 8 到 iOS 9,Sprite Kit 的性能急剧下降,原因有很多,其中一些原因您已经链接到,但还有其他原因。似乎渲染、排序和存储/处理节点的许多方面都被破坏了,或者它们以前在 CPU/GPU 上的负载增加了一倍或三倍。

但是,还有另一个问题进一步加剧了解决任何可能的性能问题的努力。这是一种普遍且看似随意的帧速率上限机制,当它以 40 fps 运行时最为明显。但它也可以在其他频率上运行。

多年来,当人们手动使用 CADisplayLink 以逐帧为基础创建游戏循环或其他基于时间的机制时,这种上限一直(很少)被注意到。

在 iOS 9 中,这种看似自动的封顶已成为基于 Sprite Kit、SceneKit、Metal 和 OpenGL ES 的应用程序的一个非常不受欢迎的“功能”。

在 SceneKit 的情况下,这是最能说明问题的,因为无论渲染选择如何 - Metal 或 OpenGL - 都会发生封顶,并且似乎在所有设备上,包括新的 6S 手机和 iPad Air 2 等设备,即使是非常简单的默认设置模板项目。

“Renderer”是设备屏幕上SceneKit的详细统计中的一个行项。这是封顶过程最有说服力的迹象。当游戏以 60fps 稳定运行时,它就不存在了。

当上限为 40 fps 时,无论在屏幕上和逻辑上执行其他活动所需的时间长短,此组件都会吸收游戏循环中保持稳定的 40 fps 上限所需的所有剩余时间。它根据其他活动所需的时间而有所不同,始终强制底层操作系统的一个明显目标是将帧速率保持在 40fps。

此问题与有关 iOS 9 Sprite Kit 性能的问题一起意味着目前可能无法解决您的所有问题。很难确定您何时达到了这些(看似)任意的 fps 上限,还是导致了实际问题。

顺便说一句,这些上限不限于 40fps。我注意到它们有 30fps、24fps、20fps、15fps、12fps 和 8fps。

当然,Apple 从未承认或承认操作系统内的这种上限机制,也没有评论它何时/如何/为何如此严重地影响游戏和渲染过程。

如本文 (Inconsistent SceneKit framerate) 中所述,我的理论是,它是 iOS 的一部分,旨在促进即将在 iPad Pro 和其他设备中使用的可变帧速率技术。

120Hz 成为未来设备的基本频率是有道理的,特别是考虑到 iOS 的性能优势、新的 Apple TV 和 iPad Pro 中的屏幕触摸/笔的 240Hz 采样......以及可观的市场上 120Hz 电视的数量。

即使没有可变帧频技术(例如...您的电视),120Hz 显示速率也意味着可以以稳定的 5:5:5 帧显示模式播放 24fps 电影 - 这大大增加了当观看电影,几乎所有电影都是以真正的 24 fps 拍摄并真正利用真正的 24fps 的模糊和运动效果的优势。

120Hz 与可变帧速率技术或 5:5:5 帧显示相比,与目前在所有设备上使用的最大帧速率为 60fps 的下拉方法相比,Apple 在电影压缩和解压缩方面也将节省大量精力.

所有猜测,但我猜在游戏引擎技术中使用这些帧速率上限也有助于降低游戏的功耗,并为(将来)开发者提供将帧速率锁定在游戏中的选项可变帧率设备世界。非常不幸的是(如果是这样的话)他们做得很差,或者解决了操作系统中的上限问题和 Sprite Kit 的性质,导致你盲目地为获得好,高,而奋斗的场景,一致的帧速率。

Apple 对这两组问题造成的问题的沉默和看似漠不关心的态度(很可能)非常强烈地表明了他们对“他们的游戏开发社区”的看法。

在一个不必要的秘密和不交流(几乎好战)的组织中,在封闭源代码框架内处理游戏制作所固有的各种尖端和性能关键开发问题是最大的单一问题。

【讨论】:

  • 嗯,这是我读过的关于这个问题的最全面的信息。不幸的是,它混淆了我最担心的问题——Apple 是故意这样做的,不考虑游戏开发者,因此不太可能修复它。我会尽量减少更新循环的使用,看看是否有帮助。在这一点上,我会对 40fps 感到满意。不过感谢您提供的信息,这有助于了解更多关于正在发生的事情,即使我似乎无能为力...
  • 抱歉,目前还没有明显的解决方案,而且缺乏来自 Apple 的沟通令人震惊。可能是第一家公开蔑视独立游戏开发商超过一代人的公司。
  • 我实际上并不认为我的问题与帧速率锁定有关。相反,正如您在开始时所建议的那样 - iOS9 由于某种原因将 CPU/GPU 负载增加了一倍或三倍。在我的 iPad2 上更新到 9.1 后,我的游戏在尝试打开之前在 iOS8 上以 60fps 运行的场景时崩溃了。我现在可能不得不将其从 App Store 下架...我想知道 Apple 是否故意这样做是为了鼓励用户升级到新硬件:/
  • 我认为这与硬件无关,因为即使是顶级硬件也存在与 iPad 2 相同的巨大性能问题。有一些图表显示从 iOS 8 到 9,所有硬件的性能都大幅下降。
  • 至于 40fps(和其他速率)的上限,无论如何您都会遇到它们......因为它们是游戏引擎/渲染器和他们使用 CADisplayLink 进行计时的天生的。由于 iOS 9 的出现,您更难看到它们,因为您在性能方面还有很多其他问题。如果您开始玩简单的项目,您会注意到帧速率上限是孤立的。
【解决方案2】:

似乎大多数 iOS9 问题都已在最新的 iOS9.2 测试版和 Xcode 7.2 测试版中得到解决。

感谢 Apple终于解决了这个问题。太糟糕了,我花了 2 个月的时间来解决问题。

我一直在 Apple 的论坛上发帖,提交错误并与支持技术人员交流。遗憾的是,Apple 从来没有明确说明他们知道哪些问题,以及 Sprite Kit 团队正在解决什么问题。

不过,至少 Sprite Kit 的大部分问题现在似乎都已解决,不再需要转行:]

【讨论】:

  • 你知道这个问题是从 iOS 7 开始修复还是从 iOS 8 开始修复?
  • 9.3 的早期测试版显示出对先前问题的一些回归,以及一些新问题。 Sprite Kit 的所有性能下降。
【解决方案3】:

在您提供的示例中,我可以看到一种提高绘制次数并验证裁剪节点是否不是问题的方法。我不知道这在您的实际游戏中有多实用,但这极大地限制了您的绘图调用。

#import "GameScene.h"

@interface GameScene ()

@property(nonatomic, strong)SKTexture *spaceshipTexture;
@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */
    SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];

    myLabel.text = @"Hello, World!";
    myLabel.fontSize = 45;
    myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
                                   CGRectGetMidY(self.frame));

    [self addChild:myLabel];

    //Create one texture to be used over an over
    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
    sprite.xScale = 0.5;
    sprite.yScale = 0.5;

    SKCropNode *cropNode = [[SKCropNode alloc] init];
    SKSpriteNode *mask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(100, 100)];
    mask.position = sprite.position;
    [cropNode setMaskNode:mask];
    [cropNode addChild:sprite];
    [self addChild:cropNode];

    //temp add to scene to create the texture than remove
    //keep pointer to texture so it can be reused
    self.spaceshipTexture = [self.view textureFromNode:cropNode];
    [cropNode removeFromParent];

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];

        //re use texture
        SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:self.spaceshipTexture];
        sprite.position = location;
        [self addChild:sprite];
    }
}

@end

缺点是当您在屏幕上显示多达 120 多个 ish 节点时,问题仍然存在。

另外请注意,我使用默认模板创建了一个全新的 SpriteKit 应用程序并删除了 SKAction。不幸的是,当您获得多达 120 个以上的节点时,即使是默认的 Apple 模板也会遭受巨大的 fps 下降。所以我不知道是否会有答案,您最好的做法是提交错误报告,因为我相信它应该(并且曾经能够)在屏幕上处理这么多的问题而不会降低 fps。

另外值得注意的是,这个错误出现在可能相关的默认项目上......

2015-10-20 10:46:50.640 Test[2218:658384] <CAMetalLayer: 0x15fe987c0>: calling -display has no effect.

更新 做更多的研究我遇到了这个......

https://forums.developer.apple.com/thread/14487

看起来其他人正在为此提交错误...

【讨论】:

  • 感谢您的努力。我已经尝试过textureFromNode,但不幸的是它在我的游戏中没有用,而且正如您所注意到的,无论如何似乎并没有改善这种情况。此外,您链接到的那个帖子包含我自己关于这个问题的帖子。我还向 Apple 提交了一个错误并用完了一个 TIS 请求。他们正在“调查”,但 Sprite Kit 团队本身没有任何消息,只是分配给我的案子的那个人......
【解决方案4】:

很多抽奖...你试过吗?

skView.ignoresSiblingOrder = YES;

【讨论】:

    【解决方案5】:

    你在使用 SKLightNode 吗?如果是这样,请尝试从您的代码中删除所有轻节点。我这样做了,我的游戏像在 iOS8 中一样以 60fps 的速度运行。

    来源:SKLightNode performance issues

    【讨论】:

      猜你喜欢
      • 2015-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-24
      • 2014-04-08
      • 1970-01-01
      相关资源
      最近更新 更多