Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layer-hosted NSView with lots of CALayers inside (WindowServer - CPU 100%)

I have an interesting case for you. And need help.

My Mac app has a layer-hosted NSView with lots of layers and sublayers and sub-sub layers inside. Imagine a Finder window with items (icons, text labels)... something like that. Each item has a button, selection background layer.

And everything is fine until you have 1000 of those items.

Now with lots of those items, my app becomes unresponsive when I try to interact with this view. And the tricky part is that it is not my app that consumes the CPU, but WindowServer. It gets to 100% and the system freezes for some time.

Important Note:

My view is a part of the app interface. There is a main window with other views. They have their own structure as well.

And I've noticed that if I put this layer-hosted view into a separate window, it works just fine with no freezes having the same 1000 items. But starts to halt the system if I put it back to the main window.

The Question

  1. What is it in my app (views/layers) that makes WindowServer go mad?
  2. Why does placing this view to a separate window helps?

I've run some tests and removed all the sublayers for every item, leaving just one-two for each. It has reduced the load on the system, but still bad. I've disabled all the drawings - just small images for the icons. Didn't help as well.

like image 693
UJey Avatar asked Oct 17 '22 06:10

UJey


1 Answers

WindowServer's main job is drawing graphics related things for macOS which means everything you can see from the entire screen, you must go through WindowServer and let it draw for you.

There are many reasons why WindowServer is using high CPU.

  1. You have complicated drawing methods in your application. -- Try to simplify your drawing method.
  2. You have a lot of graphics on the desktop so that WindowServer not only draw your application but also desktop graphics. -- Try to clean your desktop.
  3. You have some applications opened which require complicated graphics drawing? -- Try to close that application.

Until seeing your exact code, I cannot tell you why placing elements into separate window can help. Perhaps the window itself hide something to make it easier to draw?

One of my software has a lot of graphic elements and with animations. But I never have encountered your issue. How about creating a testing project and try the similar things? Sometimes, it could help to see the problem on the clearer project structure.

I created a simple demo which has 100*100 sublayers in the window. It seems no problems at all.

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Insert code here to initialize your application
    self.window.contentView?.wantsLayer = true

    let size = 10
    for i in 0..<10000 {
        let x = i%100
        let y = i/100

        let layer = CALayer()
        layer.frame = NSRect(x: x*size, y: y*size, width: size, height: size)
        layer.backgroundColor = .random()
        self.window.contentView?.layer?.addSublayer(layer)
    }

}



   func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }
}

extension CGFloat {
    static func random() -> CGFloat {
        return CGFloat(arc4random()) / CGFloat(UInt32.max)
    }
}

extension CGColor {
    static func random() -> CGColor {
        return CGColor(red:   .random(),
                       green: .random(),
                       blue:  .random(),
                       alpha: 1.0)
    }
}

enter image description here

like image 164
brianLikeApple Avatar answered Nov 02 '22 08:11

brianLikeApple