Frame rate dramatically drops down when removing node from scene

Hi all,


With the iOS 9 release I decided to remove my game from the store, because it was totally broken (Sprite kit game implemented in Swift). Meanwhile I did implement many workarounds (such as using my own gesture recognizers as sometimes nodes did not receive touch messages and so on). Now the frame rate is again at 60 fps during the entire game except for the first time two nodes are removed from the scene by the player - which is finally the goal of this game. In my game the player needs to move gaming pieces together so they are touching and will be removed. During this removement a sound is played and an SKEmitterNode shows a very short particle effect. SKEmitterNodes are also used in other parts of the game, but they are all working fine. However, for the first time two nodes are removed it takes several seconds until the scene continues to render. When I repeat this first level it works well to. I also tried the following things:


  • removed the SKEmitterNode and all SKActions, just called removeFromParent for the two nodes
  • only set the hidden property to try without any animation
  • set PreferOpenGL in info.plist


Nothing helps! I did some measurements and for me it looks like this is a CPU-bound effect, but the measured times inside my app are all very small. When I have a look at the Metal system trace using Instruments I can see a gap of nearly 2,0s where just nothing happens for exactly this situation! Meanwhile I could find the issue: its a spritekit internal call:

Running Time Self (ms) Symbol Name

1722.0ms 85.8% 0,0 __51-[SKView _vsyncRenderForTime:preRender:postRender:]_block_invoke

=> 1713.0ms 85.4% 0,0 SKCRenderer::render(SKCNode*, float vector[4], std::__1::shared_ptr<jet_framebuffer> const&, unsigned int vector[4], matrix_float4x4, bool, NSDictionary*, SKCStats*, SKCStats*)

=> 1678.0ms 83.6% 0,0 SKCRenderer::buildRenderPass(std::__1::shared_ptr<SKCRenderPass> const&)

15.0ms 0.7% 0,0 SKCRenderer::flushRenderOps()


What can I do to avoid this situation??? Or is this already a known issue of spritekit fixed in the furth-comming iOS 9.2 release? At the moment I cannot bring my game back into store, because this is not the user experience users expect on Apple devices.


Thanks a lot for any advice you can give to me...


Best regards,

Juergen

Answered by JuergenT in 91277022

After this post I dived in deeper into the stack trace of the Instruments measurement. The method buildRenderPass calls


Running Time Self (ms) Symbol Name

1673.0ms 83.4% 0,0 SKCLabelNode::rebuildFont()


When this happens a SKLabelNode will be shown with the scores for the first time using the system font. I don't know why this is an issue in iOS 9.1 on real devices and no performance issue on previous iOS versions or within the simulator, but precreating the SKLabelNode and using a copy of it for this animation did the trick! Maybe in iOS 8 and on the simulator it is not so time consuming to create a font to be used for SKLabelNode. It took me two days to find this out, but maybe this information will be helpful for others.


Best regards,

Jürgen

I forgot to mention the delay only occurs on real devices, not in the simulator!

Accepted Answer

After this post I dived in deeper into the stack trace of the Instruments measurement. The method buildRenderPass calls


Running Time Self (ms) Symbol Name

1673.0ms 83.4% 0,0 SKCLabelNode::rebuildFont()


When this happens a SKLabelNode will be shown with the scores for the first time using the system font. I don't know why this is an issue in iOS 9.1 on real devices and no performance issue on previous iOS versions or within the simulator, but precreating the SKLabelNode and using a copy of it for this animation did the trick! Maybe in iOS 8 and on the simulator it is not so time consuming to create a font to be used for SKLabelNode. It took me two days to find this out, but maybe this information will be helpful for others.


Best regards,

Jürgen

Thanks for posting. I just ran into something similar.

The first time nodeAtPoint() is called it's leading to SKCLabelNode::getBoundingBox() which triggers SKCLabelNode::rebuildFont()

Poof. First touch results in a delay.

Frame rate dramatically drops down when removing node from scene
 
 
Q