0

I want to use SpriteKit to render multiple dynamic textures updating at 30fps in a simple scene. SKMutableTexture seems like a better choice than the CGImage/CALayer combination. The SKView has its own window (as it should be possible to have multiple different views open at any time), where it's the only subview.

Unfortunately, as soon as the NSWindow with the SKView is occluded, the 'main' NSWindow with NSViews isn't really responsive (maybe 1s between events). While trying different ways to recreate the lag in a small demo project, I found out, that it happens as soon as I'm creating a SKMutableTexture (I don't even need to keep a strong reference to it). I don't even need to have a single node in my SKView. The following is the complete code for the SKScene subclass:

@implementation SampleScene
-(void)didMoveToView:(SKView *)view {
    [super didMoveToView:view];

    self.backgroundColor = [NSColor blackColor];
    SKMutableTexture *tex = [[SKMutableTexture alloc] initWithSize:CGSizeMake(10, 10)];
}
@end

My guess is, that the SKMutableTexture somehow attaches and blocks the NSRunLoop until it is ready to draw. As soon as it gets an NSWindowDidChangeOcclusionStateNotification, the SKView reduces its refresh rate, which affects the texture and therefore the run loop, by blocking it until the SKView draws again (which seems to be every second when occluded). I can circumvent this by pausing the SKView when it's window is occluded, but this doesn't seem like a good solution.

Am I doing something wrong? Are there better options than to use SpriteKit for this use case? You can download the project here (Objective-C Code, but shouldn't matter). Just try typing in the textfield with the SKView visible/occluded to test it.

I've added a simple 0.2s update for the text field in the following gif, where you can see the lag: Video showing the lag

thomasguenzel
  • 670
  • 7
  • 25
  • throw it on a background queue – Knight0fDragon Jun 19 '19 at 16:38
  • it has been a long time since I did it in objective C, otherwise I would provide an answer. – Knight0fDragon Jun 19 '19 at 16:39
  • @Knight0fDragon I wouldn't mind a Swift answer :) What do you mean by "throw it on a background queue"? Isn't the SKView required to work on the main queue? Or do you mean creating the texture on a background queue? – thomasguenzel Jun 20 '19 at 14:09
  • SKView has to work on the main queue, but you can create new objects before attaching it to your view. So you can make all the textures you want on a background thread, just don't add the sprite that is using the texture to a scene on a background thread – Knight0fDragon Jun 20 '19 at 14:16

1 Answers1

0

I would manipulate your texture in a background thread, then when finished, notifiy the main thread that the texture is ready.

In this example, I am using just an optional variable, but you could come up with better ways to notify the main thread your texture is ready

This is done in Swift:

var generatedTexture : SKTexture?
func generateTexture(){

   DispatchQueue.global(qos: .background).sync{ // we do not want 2 of these to collide with each other
       DispatchQueue.main.async{ 
           generatedTexture = nil   //clear this out to let some other check know something is being generated   
      }
      var newTexture = SKMutableTexture
      while(generatedTexture != nil){}  //freeze the thread in case generatedTexture has not set to nil yet
      //manipulate texture here
      DispatchQueue.main.async{ 
          generatedTexture = newTexture   
      }

   }
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • I've just tried this, and even when creating the texture on a background queue, it still introduces a lag on the main queue. I don't even need to have a reference to the texture. – thomasguenzel Jun 20 '19 at 15:52
  • Then something else is lagging you – Knight0fDragon Jun 20 '19 at 15:54
  • I don't have a lag when I'm not creating the texture. So it has to be related to this SKMutableTexture. My guess is that SKTexture uses an internal cache, where this mutable texture still resides (there are some hints about a private _textureCache on SKTexture). – thomasguenzel Jun 20 '19 at 15:59
  • In the sample you provided, is there that text field? I am not finding it – Knight0fDragon Jun 20 '19 at 16:02
  • There should be two windows, one with the text field (although without a timer, as I wanted to keep it really simple) and the SKView window, just try typing in the text field once with the SKView occluded and once with the SKView visible. – thomasguenzel Jun 20 '19 at 16:32