I just downloaded and ran Quartz Debug and turned on Flash Screen updates and that showed me that two little LED indicators I have on my panel which are updated at 30Hz are the cause. It looks like Quartz or JUCE is making a dirty rectangle bounding the two LEDs and a couple of sliders are in that bounding box, so they get redrawn as well.
What I don’t understand is why the dirty rectangle is so large (the rectangle enclosing both LEDs), considering that the LEDs are only 10x10 pixels.
I encountered a very similar issue last year, and nothing I have attempted so far has fixed it.
Apparently it is a shortcoming of CoreGraphics, as Jules explains in this thread:
I assume this is the problem you are encountering. I tried using the JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS macro but it didn’t reduce the number of unnecessary repaints - perhaps I am doing something wrong or misunderstanding.
This is a huge issue for me, as I have many sliders placed between meters in my plugin UI. They repaint so frequently that it spikes my CPU usage in macOSX. I have even considered a major UI redesign simply due to this issue, but it would be an unfortunate compromise. Everything works as it should on Windows.
Can you quantify this? I have on average about 8 to 16 mixer channels with faders and meters in my plugin (with the ability to have many more) and I’m not seeing a huge CPU spike on MacOS – I see far more issues in Windows in Pro Tools with slow WM_PAINT updates… but overall my plugin has the lowest CPU use in comparison to similar other plugins in it’s class.
I will check on the mac I have again at some point, but it was very substantial. The CPU hit due to graphics far outweighed that of the audio processing. This was mostly due to the fact that I had a large input and output meter on either side of my plugin and a variety of sliders and knobs in between them. This resulted in all or most of the sliders being repainted every time the meters were repainted. My slider did include shadows which were very CPU intensive.
Also note, I was testing using Ableton Live. The CPU hit due to graphics does not register on the CPU meter within Live. I had to open the activity monitor and profile the plugin in order to get a full picture of the CPU usage.
I have experimented with different times, even going low enough for the meters to appear very unresponsive. Currently the Timer is set to 30 Hz. The issue is that the sliders keep getting redrawn when they really don’t need to be. My Windows version is working smoothly without any exaggerated CPU hit. As Jules stated in the thread I linked, it is a specific issue with macOSX.
I haven’t been able to work on it for a while now, but when I get time I will revisit some proposed solutions and attempt to fix it.
JUCE_ENABLE_REPAINT_DEBUGGING is a bit more complicated than that because CoreGraphics keeps its own complex clipping region. This means that it may present the combined clip rect to JUCE, causing it to call all of the paint methods down to the the CoreGraphics calls, however CoreGraphics will only draw the actual pixels it knows internally are dirty. If you put DBG statements in component paint calls that lie in between you may well still see them being printed out.
Using JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS aims to reduce the number of paint calls simply caught up in the clipping rect but it then has the disadvantage of having to traverse the whole Component hierarchy etc. multiple times. This also has a cost associated with it.
This essentially means that you have to weigh up how much work is done in your own paint methods compared to how long CoreGraphics takes to perform the drawing routines. Minimising work done in paint routines that will never result in things actually getting drawn is one way to improve on this (e.g. use a GlyphArrangement rather than lots of drawText calls to essentially cache all the path calculations).
As always though, be sure to profile to avoid making your drawing code needlessly complex for very little benefit.
My plugin shows the exact same when using JUCE_ENABLE_REPAINT_DEBUGGING. Only my meters are shown to be repainted. However when I profiled my plugin I noticed that the sliders in between the meters were also being repainted. Try using Quarts debug to see what regions are actually being repainted - my assumption would be the entire slider/meter region at the bottom of your app.
The repainting of my meters is cheap, but the sliders in between initially consumed a lot of CPU due to shadows etc - the thought being that they would only be repainted when altered. I have indeed tried to minimise the wrk done in these paint routines to reduce this cost. Still not close to ideal though.