Optimizing the drawing

47 posts / 0 new
Last post
zamrate
Offline
Last seen: 10 months 6 days ago
Joined: 24 Sep 2007 - 17:33
Optimizing the drawing

I don't know if this still applies to the latest version, but I remember that whenever WM_PAINT was received, Component::paint() would be called for all components covered by the region passed by WM_PAINT. It would make more sense to have a backbuffer that gets retained, and only draw the components that really need it (flag them with "needsRepainting"). In the optimal case, there's no need for repainting and you can blit the backbuffer immediately. This could significantly improve the drawing speed (yes still got problems with it, as updating only the level meters in my Mixer will cause everything between all the level meters also to be repainted - the blitting itself is fast now since your update to StretchBlt).

jules
Online
Last seen: 8 min 15 sec ago
Joined: 29 Apr 2013 - 18:37
Re: Optimizing the drawing

Quote:
updating only the level meters in my Mixer will cause everything between all the level meters also to be repainted

That shouldn't be the case.. If you have components that don't intersect the complex region, then they shouldn't be repainted at all. Are you 100% sure they're not accidentally getting invalidated?

zamrate
Offline
Last seen: 10 months 6 days ago
Joined: 24 Sep 2007 - 17:33
Re: Optimizing the drawing

Let's say I have a Mixer on screen with 30 Level-Meters which are all 10 pixels in width with and 90 pixels in height, spaced at a horizontal interdistance of 30 pixels.
The top of the level meters is y=10, the bottom is at y=100.
The first level meter would be at x=10, so the next one is at x=50, and the last one of the 30 is at 10+30*40=1210 (and its Component::getRight() would return 1220).

If I call repaint() on all my MixerChannel's level meters in a same timerCallback, this will result in successive repaint() = InvalidateRect() calls for the 30 small regions, which Windows will coagulate for the next WM_PAINT and so the WM_PAINT's horizontal range will go from (x1=10, y1=10, x2=1220, y2=100). So everything in that big region will be repainted, not only the LevelMeters. Or am I completely mistaken? I don't think there'll be 30 WM_PAINT calls after 30 InvalidateRect() calls?!

jules
Online
Last seen: 8 min 15 sec ago
Joined: 29 Apr 2013 - 18:37
Re: Optimizing the drawing

Quote:
So everything in that big region will be repainted, not only the LevelMeters.

No.. There will be one WM_PAINT, but it'll provide a complex region containing your 30 rectangles. Components that don't intersect any of those rectangles won't get painted.

(Caveat: I can't guarantee that Windows hasn't got some kind of internal logic that decides that 30 regions is too complex, and just simplifies the region down to its bounding rectangle..)

You know about JUCE_ENABLE_REPAINT_DEBUGGING, right?

zamrate
Offline
Last seen: 10 months 6 days ago
Joined: 24 Sep 2007 - 17:33
Re: Optimizing the drawing

Ok, my bad. I didn't know about WM_PAINT passing complex regions. And I didn't enable JUCE_ENABLE_REPAINT_DEBUGGING either. I checked using JUCE_ENABLE_REPAINT_DEBUGGING, and indeed only the LevelMeters get repainted.
The amount of CPU used for drawing 10 level meters is about 15%. That's far too much. Other apps do this with about 2% on the same machine. I'll have to investigate what's wrong.

zamrate
Offline
Last seen: 10 months 6 days ago
Joined: 24 Sep 2007 - 17:33
Re: Optimizing the drawing

I've modified my LevelMeters code to only use 2 calls: fillRect() and drawImageRect(). Still I get a completely insane CPU usage of 40% for 20 level meters. That's just not normal.

dave96
Offline
Last seen: 37 min 52 sec ago
Joined: 27 Dec 2008 - 20:29
Re: Optimizing the drawing

When doing any kind of continual repainting I've found by far the best methods are to reduce the drawing code in the paint method as much as possible. That means calculating the pixel height of your current level and only repainting if it has changed.

I also draw and cache my meter images in resized(), one for completely on, one for completely off then you only need to draw the off image and a proportion of the on image over the top. Doing simple, non-rescaling image blits are pretty fast, much faster than any geometric drawing graphics calls. If you are doing any sort of gradient fills or alpha blending on a timer you will seriously drain the CPU.

The other thing I do is almost all my GUI processing on a background thread. This may or may not suit you but basically I only fill an AbstractFifo from my audio callback and then process it in a TimeSliceClient callback. For non-essential tasks I then just drop a few samples if it doesn't get processed in time but you could use some sort of adaptive sleep time if you need all samples processed. The advantage of this is that your main GUI remains responsive as all you are doing on the main thread is basically blitting images.

Of course you may be doing these things already but implementing these changes drastically improved the performance of my code.

TheVinn
Offline
Last seen: 3 months 6 days ago
Joined: 29 Aug 2009 - 11:31
Re: Optimizing the drawing

zamrate wrote:
I've modified my LevelMeters code to only use 2 calls: fillRect() and drawImageRect(). Still I get a completely insane CPU usage of 40% for 20 level meters. That's just not normal.

Its hard to imagine why you're having such high CPU usage. Have a look at the level meter in SimpleDJ and see how it communicates with the audio I/O callback and make sure you're doing something similar:

https://github.com/vinniefalco/AppletJUCE

(Be sure to look at the Simple DJ app).

chkn
Offline
Last seen: 1 week 1 day ago
Joined: 8 Mar 2007 - 17:17
Re: Optimizing the drawing

Are your meters opaque, and did you set setOpaque(true)? If not also the background will be redrawn.
did you limit your refreshrate (20/s)

zamrate
Offline
Last seen: 10 months 6 days ago
Joined: 24 Sep 2007 - 17:33
Re: Optimizing the drawing

The refresh rate is pretty high (about 60Hz), I'm ofcourse using setOpaque().

chkn
Offline
Last seen: 1 week 1 day ago
Joined: 8 Mar 2007 - 17:17
Re: Optimizing the drawing

Thats pretty high: - 30 fps should be enough for smooth animations and you save 50÷ Cpu : -

Pages