SoftwareRenderer produces alpha even when transparent=false?


#1

On Windows it looks like the rendering code produces an alpha channel no matter what the transparency / drop shadow setting of the ComponentPeer

juce_win32_Windowing.cpp

static bool alwaysUseARGB = isGraphicsCard32Bit(); // NB: for 32-bit cards, it's faster to use a 32-bit image.
const Image::PixelFormat format = (transparent || alwaysUseARGB) ? Image::ARGB : Image::RGB;

I agree with the comment that it is faster to use an image with 32 bits per pixel. But I would expect that it is slower to do the work of producing the alpha mask. For example, when drawing text into a Graphics using the software renderer, RenderingHelpers goes into PixelARGB::blend() instead of PixelRGB::blend(), because the destination is Image::ARGB instead of Image::RGB.

Really, what we want during ComponentPeer::handleRepaint() is to create an Image with 32 bits per pixel (i.e. pixelStride == 4) but whose format is Image::RGB. This way all of the blending code will go through the faster path where the destination is PixelRGB instead of PixelARGB. This will certainly speed up rendering across the board.

However, there’s a problem. While the Image class is very well designed and supports flexible layout of image data via the lineStride and pixelStride members, the rendering code breaks on certain combinations of pixelStride and ImageFormat!!! Case in point:

juce_RenderingHelpers.h

    template <class Iterator, class DestPixelType>
    void renderSolidFill (...)
    {
        jassert (destData.pixelStride == sizeof (DestPixelType));

This makes it impossible to render into an Image whose ImageFormat == Image::RGB but whose pixelStride == 4.

Another example:

juce_RenderingHelpers.h

    template <class DestPixelType, class SrcPixelType, bool repeatPattern>
    class ImageFill
...
                    dest++ ->blend (sourceLineStart [repeatPattern ? (x++ % srcData.width) : x++], (uint32) alphaLevel);

Here dest++ is the problem, because it ignores srcData.pixelStride and destdata.pixelStride and assumes that the stride is 3 or 4 depending on the DestPixelType template parameter.

Can we please remove the assumption in the software renderer that pixelStride == sizeof (DestPixelType) and use the pixelStride field from the Image::BitmapData for image fills, solid fills, and gradient fills?

I believe that we will improve the performance of the software renderer if we make these changes, since we will be switching to ARGB on RGB blend instead of ARGB on ARGB blend.


#2

Surprisingly, the changes weren’t that bad! I made them on my machine but Github is down so I can’t publish them yet. These are the classes that need adjustment:


EdgeTableFillers::SolidColour
EdgeTableFillers::Gradient
EdgeTableFillers::ImageFill

Each class just needed to replace “++” operations and all x coordinate offset calculations with a line that uses the appropriate pixelStride field from the BitmapData. I was able to easily preserve the optimizations (like memcpy when src, dest are both 3 bytes per pixel).

I also made a change to WindowsBitmapImage and TemporaryImage so that it produces 32 bits per pixel when the video card is 32 bit, but the Image format stays at Image::RGB (unless transparent == true). Everything looks great!


#3

Github came back, I submitted a pull request. Or if you want to manually merge the changes into a new local branch (to inspect it) here’s a link:

Web interface:
https://github.com/vinniefalco/JUCE/commits/pixelstride-fix

Git URI:
git://github.com/vinniefalco/JUCE.git

the branch is called “pixelstride-fix”


#4

Thanks Vinnie, I’ll take a look when I get chance.

For the record - and for anyone else reading this - please do NOT send me github merge requests! I always merge changes manually on my local machine, so I can clean, test, tweak (and often completely rewrite) the code before committing it. The best thing is just to fork the repo on github, make your changes, and send me a link to the diff.


#5

[quote=“jules”]Thanks Vinnie, I’ll take a look when I get chance.

For the record - and for anyone else reading this - please do NOT send me github pull requests! I always merge changes manually on my local machine, so I can clean, test, tweak (and often completely rewrite) the code before committing it. The best thing is just to fork the repo on github, make your changes, and send me a link to the diff.[/quote]


#6

Is this the diff:
https://github.com/vinniefalco/JUCE/commit/e30f2dc94c95cf33e92566597778bf46ecb9a29b

?