Drawing an image faster by fitting it to the pixel grid

(that’s not a question but some notes about how to blit a bitmap quickly on Windows, which can be made 10x faster when the correct AffineTransform is chosen with the default software render).

I’m on Windows, with the global display scaling for my 4K screen set to 125% in the windows control panel. I want to paint the background of my component with a large bitmap that has been computed to fit the pixel grid perfectly, and I want the painting to take as little cpu as possible. The physicalPixelScaleFactor reported by juce is 0.625, so I can call
g.drawImageTransformed(img, AffineTransform::scale(0.5/0.625));

That way, when I am in

juce::RenderingHelpers::SavedStateBase<juce::RenderingHelpers::SoftwareRendererSavedState>::renderImage

I can check that the final scaling is 1.0. However I’m still redirected into
juce::RenderingHelpers::EdgeTableFillers::renderImageTransformed

Why is that ? it is because there is still a very small translation remaining in the transform : (+0.25, -0.25)

If I compensate it by calling

g.drawImageTransformed(img, AffineTransform::translation(-0.25,0.25).scaled(0.5/0.625));

then I take advantage of the fast path in JUCE and the image rendering is 10x faster ! (1.2ms instead of 12ms)

Why is there a small translation amount ? it is because Graphics::setOrigin is not divisible by the scale factor. But there is a workaround, it is to use Graphics::setImageResamplingQuality(Graphics::lowResamplingQuality); before drawing the image. Then I can take advantage of the fast path without having to guess the small translation correction.

3 Likes