简体   繁体   中英

SKMutableTexture makes other Windows unresponsive when its Window is occluded

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: 显示滞后的视频

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   
      }

   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM