Repainting performance


#1

I’m writing an audio application with a few vu meters spread around the gui. The vu meters all update in response to the same timer callback, about 30 times per second. The problem is that even though the dirty regions related to these updates are very small, they are spread around the whole gui, and it seems that juce repaints all controls that fall between any dirty regions, even though they are not themselves dirty. This leads to a performance problem, since there are many controls, complicated effects &c. I’ve tried using setBufferedToImage, but that doesn’t remove the cost of compositing and effects. I’ve also tried making the vu meter components children of the top-level component and made them setOpaque, to no avail. This is my first attempt at a juce application. Any hints as to how I can improve performance? Juce 1.51, OSX 10.5


#2

I just recently had to do a similar thing with multiple meters and here’s a couple of things I did to increase performance.

What type of meter are you drawing? Obviously the simpler the design the quicker the repaints will be. Any sort of alpha blending to emulate roundness will drain more CPU than a simple opaque design. I went for a segmented meter, then you can keep a record of the current number of segments and you only need to redraw if this changes.

Secondly you might want to do your processing on a separate thread. I have a manager class that inherits from TimeSliceThread and then I register my meters that inherit from TimeSliceClient with it. Take a look at the AudioThumbnail juce class for a good example of how to use this.

Now I’m not sure if this is the best way to do it but in my audio callback I copy the samples to the meter class and set a flag to show that they are new. Then when my useTimeSlice() method is called I process the samples and calculate the new appropriate meter level. In the timerCallback I can then use this level to determine the number of segments I need to draw and only if it has changed trigger a repaint. Then you need to think carefully about the most efficient way to paint your meter but that will depend on you.

The thinking behind this was that the Meter manager class runs a very low priority thread so if the audio or message thread are hogging the CPU all that will happen is the meters wont update as often. Keeping the message thread as clear as possible helps your app run smoothly.

Anyway, this was just my approach but it seemed to work quite well, I’m sure others will have better ideas.


#3

Hello and thanks for your hints which are all good and sound, but I don’t think they quite solve my problem. The audio processing is done in a separate thread and the meters themselves repaint in no time at all. The problem I’m trying to get around is that other components are also redrawn even though they wouldn’t have to. Let’s say the gui looks something like this:

===meter1=== ===meter2===

     expensive component

===meter3=== ===meter4===

Each time I update the four meters, the component(s) in the middle are also repainted even though there is no overlap with the meters. In this case, they have an expensive graphical effect on them which I don’t want to run for every display frame.


#4

Haven’t seen that behaviour myself. Have you tried setting JUCE_ENABLE_REPAINT_DEBUGGING in juce_config.h to true? This makes a repainted area change colour when a repaint occurs so you can see what is actually getting repainted and how often. In my case only my meters flash (as they are constantly repainted), not the components in between.


#5

I didn’t know about that flag, so I actually did the precise same thing myself - painting a random background color. And the result, whether I use JUCE_ENABLE_REPAINT_DEBUGGING or my own thing is that only the vu meters themselves “flash”. But that is a bit misleading, because the flashing only shows the clipping mask and not which components are asked to repaint. If I print debugging messages in the overloaded paint() and applyEffect() methods, I see that they are actually called even on the components in the middle. They perform a ton of drawing operations that have no effect because they are outside the clipping mask. All these null operations end up taking more time than the actual painting. Well, well. I’ve made my expensive graphical effect less expensive now, so the issue is not a show-stopper.