We have a plugin UI which features a large animated graph window, together with several other animated components. Drawing performance has proved to be problematic on OSX, seemingly with drawing images under Core Graphics accounting for most of the work.
We’d defined the JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS macro, and found that this speeded things up significantly owing to the fact that it reduces the area which needs to be redrawn every frame significantly.
However, I recently upgraded to a new (Touch Bar) MacBook Pro with Mojave, and noticed that once again, the plugin UI is sluggish. Part of this is likely down to the high DPI screen increasing the amount of blitting work required, however I’ve also noticed when using Quartz Debug that the UI is no longer rendering the updated regions separately, but has reverted to updating a single large rectangle encompassing all the components which have changed.
Has anybody else experienced this, or can any of the Juce team shed some light on the situation? Any help much appreciated!
In NSViewComponentPeer::drawRect() when that flag is enabled we’re calling getRectsBeingDrawn()here which should return a list of non-overlapping dirty rectangles to be repainted. This works correctly in macOS versions < 10.14 and we get a list of rectangles that can be painted separately, but in 10.14, like you say, it seems that getRectsBeingDrawn() is always just returning one all encompassing rectangle for the dirty regions.
It seems like this is a bug in 10.14 as I can’t see any changes to that method or notes in the Apple API docs saying that its behaviour has changed.
I just did a quick test this morning by enabling the JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS flag and setting a breakpoint at this line. When building against the 10.13 SDK it is hit fairly often but when using Xcode 10 and building against 10.14 it is never hit.
In that case, a potential solution is to add components as “heavyweight” components on iOS using addToDesktop, so each major component is in its own UIView. You would then need to manage these in a UIViewController using Objective-C or Swift.