Just keep in-mind regarding JUCE comptability.
This requires macOS 10.8+.
(currently JUCE minimum target is 10.7).
Can I ask what exactly you added where?
I’d like to test this out.
I think I tried the wantsLayer
in the past and it didn’t seem to do much (IIRC because top-level windows are always layer backed).
Do you know if it’s the drawsAsynchronously
flag that gave you a big speedup?
Wow. Adding:
[view setWantsLayer: YES];
[[view layer] setDrawsAsynchronously: YES];
just under the [view setPostsFrameChangedNotifications: YES];
line takes me from about 10fps to 60fps. It’s like night and day.
I have noticed some graphical glitches but they look like they’re to do with dirty rects (or maybe aliasing) that I can probably work around.
It also looks like you can’t have transparent windows with one of those flags (CallOutBoxes etc.) so I’ll need to do some investigation there too.
Thanks @olilarkin and @basteln and everyone else…
I can confirm that the update fixes my issue on my iMac Pro using the iMac Pro Color profile. In fact, I even noticed a bit more detail in the graphics (could be euphoria haha). Resizing is faster and overall it feels like a new plugin graphics-wise.
So adding these flags only to opaque components seems to work very well:
if (component.isOpaque())
{
[view setWantsLayer: YES];
[[view layer] setDrawsAsynchronously: YES];
}
I managed to work around my graphical glitch by snapping the lines to 0.5px boundaries.
Would it be possible to get these flags added to JUCE under a special “beta” (JUCE_NSVIEW_DRAWS_ASYNCHRONOUSLY
or similar) macro so I can send a version out to beta testers?
I’d like to see if any more glitches are found before committing to this completely.
Digging a little deeper in to the stack traces of the profile, it looks like doing this enables the graphics to be rendered using Metal. It also puts the drawing on background threads which frees up a lot of time on the message thread.
I’m really impressed by this. Kudos to @olilarkin for sharing.
This may have been the biggest find of the year.
Wishful thinking here, but does this translate to iOS as well?
Sure! I also read your other posts below this one, and what I did is almost the same. I added this:
view.wantsLayer = YES;
view.layer.drawsAsynchronously = YES;
…in between the view = [createViewInstance() initWithFrame: r];
and the setOwner (view, this);
.
Wishful thinking here, but does this translate to iOS as well?.
I’ll try it. On iOS, a CALayer is always used, but the drawsAsynchronously
is off by default and can be turned on just as on macOS. We’ll see how much it affects speed on iOS.
This is ridiculously effective
Just tried it on iOS, can confirm that just by setting drawsAsynchronously
to YES
I get a major speedup in our app. The Apple doc for drawsAsynchronously
says to measure and compare, but IMO it’s worth trying out
@olilarkin Thanks so much, once again.
@basteln Now this doesn’t solve our rects painting and drawing the entire interface stuff as per (https://forum.juce.com/t/re-solved-repaint-ignores-opacity-and-repaints-parent-component/35597/2)? Actually, what is going on…Are we now using Metal as per what @dave96 suggested?
I think what happens with the async and layer flags is that:
- The window has a CA layer which creates a Metal context to draw on to
- In your
paint
method, instead of directly drawing on to the screen via CoreGraphics, these instructions get queued up - Another thread(s) then dispatch the graphics calls using Metal on to the context
This is just a rough guess from looking at the profile trace though. I’m not a Metal expert so if anyone has more insight I’d be keen to hear.
This has been added on the develop
branch in a277256, so you can enable the JUCE_COREGRAPHICS_DRAW_ASYNC
flag to test it out.
Thanks @ed95, I think you need to wrap it in an if (component.isOpaque())
check though or window transparency is broken.
Ah OK, will do.
I found this worked on all the transparent components in my UIs, so might be better to disable it a bit more selectively to maximise the performance gains if possible.
Yeah, @ed95 worked it out so it works on transparent windows too now.
You have to set the window to a “clear” background which was only being done for newer SDKs. Removing the SDK check seems to resolve it on all targets.
This is awesome ! I’m putting the two magic lines enclosed in a
if (floor(kCFCoreFoundationVersionNumber) >= kCFCoreFoundationVersionNumber10_8)
so that I can still target macOS 10.7, and take advantage of this improvement on later macOS versions.
Just tried and I notice a real difference on my 2019 5k iMac.
@jules You guy should definitely have a look after ADC.
Thanks !
Annoyingly it looks like some plugins have an issue with this flag set. At the moment we’ve had reports of Waves Gold V10 and some Izotope plugins just showing a blank UI with this flag set.
Even more annoyingly though, the most recent versions of these plugins seem to work (Waves V11 etc.) but we have a lot of users still on V10.
It looks like we might have to add a way to disable this on a per-window basis so I can simply not use it for plugins windows. Maybe another ComponentPeer::StyleFlags
?