Optimizing the drawing

Discussion and support for general JUCE issues

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 6:28 am

I think that Windows will sometimes consolidate many rectangles under some circumstances.

No it doesn't, I checked via repaint debugging. Same happens on OSX.
Interestingly, if I call getPeer()->performAnyPendingRepaintsNow() after calling repaint() on the first 30 level meters, then do the same after calling repaint() on the next 30 level meters, then the CPU goes down by nearly 50%!
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 6:30 am

Here is an example of the other sort of optimisation I was talking about, caching to images
.
Seems to only make everything slower. I was also using drawImageAt() instead of fillRect() in my other code, but it's definitely slower.
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 6:44 am

Here are some results, make with Shark on OSX:

With call to ComponentPeer::performAnyPendingRepaints() every 30 level meters, after calling repaint on each of these 30 level meters in the timerCallback().
with performanypendingrepaints.png
with performanypendingrepaints.png (183.98 KiB) Viewed 458 times


And without (normal repaint() to all 60 level meters in the timer callback):
without performanypendingrepaints.png
without performanypendingrepaints.png (171.04 KiB) Viewed 458 times


We can see that the distribution of CPU time is completely different in both cases.
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:04 am

SolidColourEdgeTableRenderer shouldn't even be part of the profile, nor should aa_render_shape. The fastest method of drawing level meters is to fill solid rectangles with no blending or anti-aliasing. Juce correctly detects the optimized case of a solid colour rectangle aligned on integer coordinate boundaries and switches instead to a straight fill, this happens here:

juce_RenderingHelpers.h
Code: Select all
    void fillRect (const Rectangle<int>& r, const bool replaceContents)
    {
        if (clip != nullptr)
        {
            if (transform.isOnlyTranslated)
            {
                if (fillType.isColour())
                {
                    Image::BitmapData destData (image, Image::BitmapData::readWrite);
                    clip->fillRectWithColour (destData, transform.translated (r), fillType.colour.getPixelARGB(), replaceContents);
                }
                else
                {
                    const Rectangle<int> totalClip (clip->getClipBounds());
                    const Rectangle<int> clipped (totalClip.getIntersection (transform.translated (r)));

                    if (! clipped.isEmpty())
                        fillShape (new ClipRegions::RectangleListRegion (clipped), false);
                }
            }
            else
            {
                Path p;
                p.addRectangle (r);
                fillPath (p, AffineTransform::identity);
            }
        }
    }


fillRectWithColour instead of fillShape is going to be orders of magnitude faster...draw the level meter using only calls to Graphics::fillRect() using fully opaque colours and no transform.
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 7:09 am

Thanks Vinn, I did exactly that. Only using fillRect() for the profiling and I also tested with setPaintingIsUnclipped(true) on all LevelMeters, no difference. If you don't trust the results above, please feel free to use your own profiler and check.
Last edited by zamrate on Thu Jun 07, 2012 7:16 am, edited 1 time in total.
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:12 am

Why is SolidColourEdgeTableRenderer showing up then?
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:14 am

I did some performance tests with setPaintingIsUnclipped() way back when and didn't see any appreciable difference in the profile.
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:17 am

I believe that the top spot of getARGB() is a symptom of calling PixelARGB::blend(). There's no good reason for this function to be called when drawing solid rectangles. That, and because we're seeing SolidColourEdgeTableRenderer makes me think that your response to Component::paint() is drawing anti-aliased polygons which is a ticket to the slow lane.
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 7:18 am

Why is SolidColourEdgeTableRenderer showing up then?

Maybe it's showing up because I'm using the CoreGraphics renderer?

[EDIT: NO I WASN'T]
Last edited by zamrate on Thu Jun 07, 2012 7:43 am, edited 1 time in total.
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:21 am

zamrate wrote:
Why is SolidColourEdgeTableRenderer showing up then?

Maybe it's showing up because I'm using the CoreGraphics renderer?


Hmm....what's the point of using CoreGraphics if it doesn't rasterize polygons for you using some kind of "extra" (hardware acceleration if available)? Try turning it off and look at the profile.

There should be absolutely NO blending of any sort going on if you are only going through YourLevelMeter::paint().
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:25 am

Looking at the profile and the Juce code, I see some things I don't like:

juce_RectangleList.cpp
Code: Select all
Rectangle<int> RectangleList::getRectangle (const int index) const noexcept
{
    if (isPositiveAndBelow (index, rects.size()))
        return rects.getReference (index);
    return Rectangle<int>();
}


Say what? Every call to getRectangle() is bounds-tested?

The prominence of RectangleList::subtract probably has to do with EdgeTableRegion::clipToRectangleList. Obviously the run time of clipToRectangleList() is linear with the number of rectangles and we're paying for that ridiculous isPositiveAndBelow which is totally unnecessary. Going from 60 to 30 rectangles in the rectangle list will cut the number of calls to clipToRectangleList() exactly in half, consistent with your observation of performPendingRepaintsNow() behavior.

It looks like Jules has some profiling to do, after all of the changes to rendering some hot spots have reared their ugly head again!
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:37 am

This is troubling:

juce_mac_CoreGraphicsContext.cpp
Code: Select all
bool CoreGraphicsContext::clipToRectangleList (const RectangleList& clipRegion)
{
    if (clipRegion.isEmpty())
    {
        CGContextClipToRect (context, CGRectMake (0, 0, 0, 0));
        lastClipRectIsValid = true;
        lastClipRect = Rectangle<int>();
        return false;
    }
    else
    {
        const int numRects = clipRegion.getNumRectangles();

        HeapBlock <CGRect> rects (numRects);
        for (int i = 0; i < numRects; ++i)
        {
            const Rectangle<int>& r = clipRegion.getRectangle(i);
            rects[i] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight());
        }

        CGContextClipToRects (context, rects, numRects);
        lastClipRectIsValid = false;
        return ! isClipEmpty();
    }
}


Heap block allocation, followed by O(N) operation where N =~ number of rectangles in the clip (30 or 60 in your case).

If all else fails, instead of calling repaint() on a batch of 30 and then performPendingRepaintsNow() try doing them one at a time so the clip only has a single rectangle.
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby TheVinn » Thu Jun 07, 2012 7:39 am

Anyway, that's about all I can think of. Sniff around and find out why there's blending going on, and why if you're using CoreGraphics that JUCE is doing the rasterization manually. I will be interested to see what we find tomorrow because my app performs like a champ on Windows but on the Macintosh when I resize my main application window it is clunky and moves like my grandmother in a nursing home.
Open Source: LayerEffects, VFLib, SimpleDJ, DSP Filters, LuaBridge, JUCE, FreeType, TagLib
"This isn't a big project, it shouldn't take long." - Jules
User avatar
TheVinn
JUCE UberWeenie
 
Posts: 2975
Joined: Sat Aug 29, 2009 11:31 am
Location: Marina del Rey, California

Re: Optimizing the drawing

Postby zamrate » Thu Jun 07, 2012 7:44 am

I didn't use the CoreGraphics renderer, I checked. Calling performAnyPendingRepaints() on every component makes the CPU jump up a lot. It's not a good idea, I tried it too.

Anyway, the core problem seems to be that when the list op clipping rectangles gets as high as 60, JUCE is spending more time with doing manipulations on that list then the on the actual drawing itself.
User avatar
zamrate
JUCE UberWeenie
 
Posts: 1081
Joined: Mon Sep 24, 2007 5:33 pm

Re: Optimizing the drawing

Postby chkn » Thu Jun 07, 2012 8:07 am

Why don't you use the CoreGraphics Renderer?
chkn
JUCE UberWeenie
 
Posts: 861
Joined: Thu Mar 08, 2007 6:17 pm

PreviousNext

Return to General JUCE discussion

Who is online

Users browsing this forum: Google Feedfetcher and 1 guest

cron