Graphics::fillRect and replaceExisting Working As Designed


#1

When replaceExisting == true, solid colour rectangles on integer coordinates with only a translation skip RGB blending and instead perform a much faster copy operation.

But when does replaceExisting ever get set? Graphics::fillRect() passes false regardless of the type of fill.

Given zamrate’s profile and his claim of only drawing solid colour rectangles, it seems this optimization is broken in the latest tip.


#2

It’s only available if you call the low level context object directly. Because of the specificity of the situations where it can be used, it’s more of an “expert” option, and I didn’t want to complicate the Graphics class with it.


#3

Sure but how do you use it in Component::paint() overrides? There’s no replaceExisting parameter to Graphics::filRect(). Are you expecting users to call Graphics::getInternalContext()->fillRect(…, true)? Is this really what you want?


#4

Nope. I’m not expecting anyone to use it for painting components, because it’s completely meaningless in any context that isn’t specifically drawing into an Image. It only makes sense to use it when you’re drawing into an Image, so it’s used in things like Image::clear().

What you’re talking about is different - you want to avoid blending in circumstances where you’re drawing a solid colour, but that’s not something that you need to set a flag to make it happen, it’s just something that the rendering code should do internally whenever possible.


#5

Yes I see. You are right. But then we have a bug, because this behavior doesn’t seem to be happening (see zamrate’s profile):

juce_GraphicsContext.cpp

void Graphics::fillRect (int x, int y, int width, int height) const
{
...
    context->fillRect (Rectangle<int> (x, y, width, height), false);
...

juce_LowLevelGraphicsSoftwareRenderer.cpp

void LowLevelGraphicsSoftwareRenderer::fillRect (const Rectangle<int>& r, const bool replaceExistingContents)
{
    savedState->fillRect (r, replaceExistingContents);
...

juce_RenderingHelpers.h

void SoftwareRendererSavedState::fillRect (const Rectangle<int>& r, const bool replaceContents)
...

Graphics::fillRect() always passes false for replaceContents, which makes its way through to EdgeTableFillers::SolidColour as false, meaning that we use blend for every pixel instead of a copy.


#6

Yeah, I stopped taking zamrate’s profile very seriously when he said that he’d profiled a debug build.

The relevant checks for fully-opaque pixels happen inside EdgeTableFillers::SolidColour.


#7

It definitely goes through here:

juce_RenderingHelpers.h

        forcedinline void handleEdgeTableLineFull (const int x, const int width) const noexcept
        {
            PixelType* dest = linePixels + x;

            if (replaceExisting || sourceColour.getAlpha() >= 0xff)
                replaceLine (dest, sourceColour, width);
            else
                blendLine (dest, sourceColour, width);
        }

Correctly calling replaceLine() instead of blendLine(). NOT BROKEN - working as designed.