Optimize INV_PREMUL

Our inverse premultiply is rather unoptimized. It's major weakness is
using three divide operation which are the slowest integer operations.

This patch reduces the three divisions to just one but using an
approximation that is accurate for all uchar values.

The patch also adds a general short-cut for alpha==255.

Together these improvements makes it 2 to 16 times faster depending on
how many 0 and 255 alpha values are encountered.

Change-Id: I96d7098a1bc320793b0d0526637acd1fdb5a43eb
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
bb10
Allan Sandfeld Jensen 2014-01-15 15:02:09 +01:00 committed by The Qt Project
parent 93a895a41a
commit 407eee51e6
2 changed files with 11 additions and 7 deletions

View File

@ -274,7 +274,7 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src
if (!layout->premultiplied) {
for (int i = 0; i < count; ++i)
buffer[i] = qAlpha(src[i]) == 255 ? src[i] : INV_PREMUL(src[i]);
buffer[i] = INV_PREMUL(src[i]);
src = buffer;
}
for (int i = 0; i < count; ++i) {

View File

@ -691,12 +691,16 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) {
return t;
}
#define INV_PREMUL(p) \
(qAlpha(p) == 0 ? 0 : \
((qAlpha(p) << 24) \
| (((255*qRed(p))/ qAlpha(p)) << 16) \
| (((255*qGreen(p)) / qAlpha(p)) << 8) \
| ((255*qBlue(p)) / qAlpha(p))))
static Q_ALWAYS_INLINE uint INV_PREMUL(uint p) {
const uint alpha = qAlpha(p);
if (alpha == 255)
return p;
if (alpha == 0)
return 0;
// (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256.
const uint invAlpha = 0x00ff00ffU / alpha;
return qRgba((qRed(p)*invAlpha)>>16, (qGreen(p)*invAlpha)>>16, (qBlue(p)*invAlpha)>>16, alpha);
}
struct quint24 {
quint24(uint value);