Hi Jules, everybody,
I spotted a ~33% overall performance improvement in my plug-ins when optimizing some drawings (mac/coregraphics). Here are my finding:
When drawing my plug-ins’ background images, I tried and clipped it to the given Context’s bounds. This did a great performance boost, which I couldn’t event obtain with setBufferedToImage(true);.
I then thought that if it was the case for this image, it could be the case for any image drawing, so I transfered my clipping part to the Graphics::drawImageAt() method:
[code]void Graphics::drawImageAt (const Image& imageToDraw,
const int topLeftX, const int topLeftY,
const bool fillAlphaChannelWithCurrentBrush) const
{
Rectangle clipBounds = context.getClipBounds();
Rectangle imageBounds (topLeftX, topLeftY,
imageToDraw.getWidth(), imageToDraw.getHeight());
if (clipBounds.intersects(imageBounds))
{
Rectangle<int> intersection = clipBounds.getIntersection(imageBounds);
Image clippedImage = imageToDraw.getClippedImage (intersection
.translated (-topLeftX, -topLeftY));
jassert(intersection.getWidth() == clippedImage.getWidth());
jassert(intersection.getHeight() == clippedImage.getHeight());
int imageW = clippedImage.getWidth();
int imageH = clippedImage.getHeight();
drawImage (clippedImage,
intersection.getTopLeft().x, intersection.getTopLeft().y, imageW, imageH,
0, 0, imageW, imageH,
fillAlphaChannelWithCurrentBrush);
}
}[/code]
That worked as well. But I could make it even more general in the Graphics::drawImage method instead, when the transform is just a translation (width and height conserved):
[code]void Graphics::drawImage (const Image& imageToDraw,
int dx, int dy, int dw, int dh,
int sx, int sy, int sw, int sh,
const bool fillAlphaChannelWithCurrentBrush) const
{
// passing in a silly number can cause maths problems in rendering!
jassert (areCoordsSensibleNumbers (dx, dy, dw, dh));
jassert (areCoordsSensibleNumbers (sx, sy, sw, sh));
Rectangle<int> clipBounds = context.getClipBounds();
Rectangle<int> destRegion (dx, dy, dw, dh);
if (imageToDraw.isValid() && clipBounds.intersects (destRegion))
{
if (dw == sw && dh == sh)
{
Rectangle<int> intersection = clipBounds.getIntersection (destRegion);
Image clippedImage = imageToDraw.getClippedImage(intersection
.translated (sx - dx, sy - dy));
jassert(intersection.getWidth() == clippedImage.getWidth());
jassert(intersection.getHeight() == clippedImage.getHeight());
drawImageTransformed(clippedImage,
AffineTransform::identity
.translated (intersection.getTopLeft().x,
intersection.getTopLeft().y),
fillAlphaChannelWithCurrentBrush);
}
else
{
drawImageTransformed (imageToDraw.getClippedImage (Rectangle<int> (sx, sy, sw, sh)),
AffineTransform::scale (dw / (float) sw, dh / (float) sh)
.translated ((float) dx, (float) dy),
fillAlphaChannelWithCurrentBrush);
}
}
}[/code]
And that has also worked well; it also covers the drawImageAt optimization case (so, forget the first snippet). The previous drawImage implementation was not as efficient because the clipping was to the source dimensions instead of the clipped dimensions. Source dimensions are often the whole image. Having more than the clipped image is indeed required when the transform is not only a translation (hence, requiring some inter-pixel computations a the clipped borders), however in many cases the transform is only a translation, notably in the drawImageAt call.
I don’t know if this optimizes very specifically in the CoreGraphicsContext case or if it is more general; however the last code snippet’s overhead is insignificant, so I would greatly recommend including it in Juce.
All the best