Laggy GUIs on OSX El Capitan?

It looks like the Reaper guy found a solution

 

http://forum.cockos.com/showthread.php?t=169884

 

Maybe worth contacting him ?

From that thread it sounds like he tried some workarounds but wasn't really successful - people were still saying it didn't work on some machines.

This is a really annoying one, it might be something that Apple has to sort out. But it sounds like many other apps are struggling with it too.

I'd like to do some work on finding a workaround for this, but am struggling to reproduce it!

What I need is a standalone app that produces this behaviour so I can investigate what's happening, but nothing I try seems to make it go wrong..

Does anyone have any tips or code samples that I could try? It seems to have something to do with host + plugin interactions, so I've tried apps with a couple of windows that both repaint rapidly, but even that seems to run just fine. Help!

 

FYI, I've posted a change which may be related (though I still don't have a good test for the thing that people are discussing in this thread).

These changes are to help with jerky window resizing, which I think is a similar problem. It may also be that the workarounds I added can be used to sort out this problem, if we can narrow down exactly what's going on.

I was finally able to reproduce it in a simplified example. I'll send that later tonight. Thanks for looking into this. 

Ok, it's a bit of a convoluted example but this should reproduce the lag we're experiencing: 

http://s000.tinyupload.com/?file_id=34159458351635324492

You can change the macro values to try different combinations. You should see the toggle button become laggy/unresponsive once animation starts. 

Thanks, very useful!

It's still a mystery to me about exactly what Apple changed, but it seems that they're simply throwing away some of our repaint requests.

As a workaround, I've added a step where the juce code manually coalesces repaint regions, which fixes the problem in this example, at least. Hopefully it'll also sort out your real app too - if not, please send me more example code and I'll look again!

Great! Thanks a million. We're a few steps back on JUCE right now but we'll update this week and hopefully let you know that the fix was successful. 

Jules-

We're also a few steps back on JUCE, but dropping in the changes from your commit to test here seems to have solved (or at least, greatly improved) the issue. We'll definitely update soon. Thanks so much for looking into this!

Best,

Tom

I've been seeing similar issues, since OS X El Capitan - my plug-ins don't use JUCE, but I think the mechanism for UI redraws is similar. Basically the UI is drawn offscreen to a pixel buffer (just a block of memory notionally RGBA format) and then in drawRect for the plug-in's NSView, the area of offscreen memory is copied to theNSView using a Bitmap context and a CGImageRef. So normally, if the user drags a control, the mouseDragged method updates the control's value, tells the host etc, redraws the control into the offscreen memory, then posts a setNeedsDisplayInRect to signal the redraw. drawRect then gets called and the control's new state becomes visible. All works well until El Capitan. Since EC, the control animates smoothly, but the NSTimer object used for updating the plug-in's meters etc, seems to get locked out while the mouse is moved. Normally this would indicate the NSTimer isn't registered for the right runloop modes e.g. NSEventTrackingRunLoopMode, however this is in place, and it can be shown to work on previous OS X. I've noticed that when this happens, it also blocks meter updates in Logic Pro X  (some JUCE plug-ins I've tested also seem to cause this). 

I wonder if it might be, that there is some new mode like NSEventTrackingRunLoopMode, added in OS X EC, for which we are not registering events - or that locks out timer updates for other reasons, which is unfortunately causing these problems. It might be a crazy idea, but it would fit the evidence I have. I can't see that its an issue with too many updates getting queued (differently) and / or getting dropped as a result, since that path through my code seems to work as expected.

From my reading of Apple's documentation about the runloop sequence of events (which they point out is - 'very specific' ) - it would appear that the runloop should always callback handlers for NSTimers which have fired, before processing other events - so, irrespective of the time taken to process the mouseDragged, and associated redraw,  in my code, for example, the timer should simply fire on the next runloop, which is what it used to do. Even for insane fullscreen redraws at retina resolution (as a stress test).

After much further testing it seems that this is not a thread related or RunLoop mode issue (as some of our previous lines of inquiry suggested) and what we are seeing suggests that the RunLoop behaviour on El Capitan simply doesn't allow for NSTimers, GCD timers or other background events on the main loop to be serviced with the same regularity / reliability as on previous versions, if for example, the system is busy with pending mouse input. Which leads us back around to this looks like something Apple changed, possibly intentionally, possibly not, and no reliable resolution to the problem, which is deeply frustrating.

Yes, very frustrating. They did definitely mess with something in the runloop servicing, but really stuck for ideas on how to find a workaround.

Has anyone reached out to Apple about this? I know they usually aren't very forthcoming with information regarding these types of problems, but it's possible that they either aren't aware or haven't heard many complaints about this issue, and therefore won't take steps to address it. It sounds like it is affecting non JUCE-based applications too, so they might more seriously consider addressing it. Just a shot in the dark here, though.

I've submitted a bug report to Apple - not sure if they will regard this as a bug, but I certainly do... I await a response - but I'm not optimistic.

I did some tests on OS X El Captian vs OS X 10.8 and in a more general test case I found that just doing anything which took longer than about 15ms to complete (even a usleep(some tme) ) in the mouseDragged callback of my plug-in NSView - without any UI redraws, caused an NSTimer on the main RunLoop registered with NSRunLoopCommonModes to stop firing while the mouse was moving. In contrast on 10.8, you can increase the usleep interval to relatively much longer intervals, and while the timer fires at a progressively slower rate, as to be expected as the RunLoop spends more and more time in the mouseDragged callback, it doesn't seem to freeze up. It continues to be called.

So it would appear that whatever changed, it means that if mouse input events queue up faster than they can be handled, the RunLoop becomes bound up processing them and now, never checks /  services expired timers (or other processing further down the loop).

It could be a deliberate design change, but I hope not (though, it could be hypothesised that this kind of agressive focus on processing user input to the exclusion of any other background tasks makes more sense on e.g. an iPhone than it does on the desktop, with all that that implies...)

(I've also noticed similar issues in ProTools with freezing meters etc, and affecting some of Avid's plug-ins in a similar way)

It took much longer than expected but we finally updated to the latest version of JUCE to confirm the fix and it worked perfectly. Thanks again Jules.

Did anyone come up with an easy fix? Using Logic, and every time I drag a Component (repainting in MouseDragged), Logics VU Meters and other Animations become super choppy!! Help!!

Are you on the latest tip? Jules added a workaround for this a while back (it still manifests itself occasionally but is much better), and I believe Fabian added a workaround to a somewhat related automation issue in Logic (Steppy automation recording on OSX).

Make sure you aren’t calling repaint() unnecessarily…if you’re using the Slider class hooked up correctly, then dragging the mouse should trigger a setValue() call, which will call repaint() as necessary.

Could you direct me to getting the latest version? I’m a bit of a noob in that regard. I am using 4.2.3… But can’t seem to find shouldThrottle as Jules suggested.

Thanks!

https://github.com/julianstorer/JUCE/tree/develop

All is well. Thanks folks.