summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-01-29 11:41:31 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-10 12:49:06 +0100
commita7b8ef08415b8056661c3db5950842ee546891b9 (patch)
treef010dbec1421980535be48705b51b7c62d079a16 /src/gui/painting
parent143d591aab7a2d244913e9d13f079de05eb7a65c (diff)
Export optimized premultiply and unpremultiply methods
This patch optimizes the unpremultiply method further by using a lookup table to avoid any divisions at all. The opportunity is taken to export both premultiply and unpremultiply since they are commonly used methods relevant to the exported QRgb type that can be both premultiplied and unpremultipled ARGB. [ChangeLog][QtGui][QColor] Exported highly optimized methods for premultiply and unpremultiply of QRgb values. Change-Id: I658bcf57b0bc73c34c1765b64617d43b63ae820b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qcolor.cpp55
-rw-r--r--src/gui/painting/qdrawhelper.cpp30
-rw-r--r--src/gui/painting/qdrawhelper_p.h35
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp38
-rw-r--r--src/gui/painting/qrgb.h43
5 files changed, 136 insertions, 65 deletions
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 706273c151..b9d3ca888e 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -2499,6 +2499,41 @@ QDataStream &operator>>(QDataStream &stream, QColor &color)
}
#endif // QT_NO_DATASTREAM
+// A table of precalculated results of 0x00ff00ff/alpha use by qUnpremultiply:
+const uint qt_inv_premul_factor[256] = {
+ 0, 16711935, 8355967, 5570645, 4177983, 3342387, 2785322, 2387419,
+ 2088991, 1856881, 1671193, 1519266, 1392661, 1285533, 1193709, 1114129,
+ 1044495, 983055, 928440, 879575, 835596, 795806, 759633, 726605,
+ 696330, 668477, 642766, 618960, 596854, 576273, 557064, 539094,
+ 522247, 506422, 491527, 477483, 464220, 451673, 439787, 428511,
+ 417798, 407608, 397903, 388649, 379816, 371376, 363302, 355573,
+ 348165, 341059, 334238, 327685, 321383, 315319, 309480, 303853,
+ 298427, 293191, 288136, 283253, 278532, 273966, 269547, 265268,
+ 261123, 257106, 253211, 249431, 245763, 242201, 238741, 235379,
+ 232110, 228930, 225836, 222825, 219893, 217038, 214255, 211543,
+ 208899, 206320, 203804, 201348, 198951, 196611, 194324, 192091,
+ 189908, 187774, 185688, 183647, 181651, 179698, 177786, 175915,
+ 174082, 172287, 170529, 168807, 167119, 165464, 163842, 162251,
+ 160691, 159161, 157659, 156186, 154740, 153320, 151926, 150557,
+ 149213, 147893, 146595, 145321, 144068, 142837, 141626, 140436,
+ 139266, 138115, 136983, 135869, 134773, 133695, 132634, 131590,
+ 130561, 129549, 128553, 127572, 126605, 125653, 124715, 123792,
+ 122881, 121984, 121100, 120229, 119370, 118524, 117689, 116866,
+ 116055, 115254, 114465, 113686, 112918, 112160, 111412, 110675,
+ 109946, 109228, 108519, 107818, 107127, 106445, 105771, 105106,
+ 104449, 103800, 103160, 102527, 101902, 101284, 100674, 100071,
+ 99475, 98887, 98305, 97730, 97162, 96600, 96045, 95496,
+ 94954, 94417, 93887, 93362, 92844, 92331, 91823, 91322,
+ 90825, 90334, 89849, 89368, 88893, 88422, 87957, 87497,
+ 87041, 86590, 86143, 85702, 85264, 84832, 84403, 83979,
+ 83559, 83143, 82732, 82324, 81921, 81521, 81125, 80733,
+ 80345, 79961, 79580, 79203, 78829, 78459, 78093, 77729,
+ 77370, 77013, 76660, 76310, 75963, 75619, 75278, 74941,
+ 74606, 74275, 73946, 73620, 73297, 72977, 72660, 72346,
+ 72034, 71725, 71418, 71114, 70813, 70514, 70218, 69924,
+ 69633, 69344, 69057, 68773, 68491, 68211, 67934, 67659,
+ 67386, 67116, 66847, 66581, 66317, 66055, 65795, 65537
+};
/*****************************************************************************
QColor global functions (documentation only)
@@ -2581,6 +2616,26 @@ QDataStream &operator>>(QDataStream &stream, QColor &color)
*/
/*!
+ \fn QRgb qPremultiply(QRgb rgb)
+ \since 5.3
+ \relates QColor
+
+ Converts an unpremultiplied ARGB quadruplet \a rgb into a premultiplied ARGB quadruplet.
+
+ \sa qUnpremultiply()
+*/
+
+/*!
+ \fn QRgb qUnpremultiply(QRgb rgb)
+ \since 5.3
+ \relates QColor
+
+ Converts a premultiplied ARGB quadruplet \a rgb into an unpremultiplied ARGB quadruplet.
+
+ \sa qPremultiply()
+*/
+
+/*!
\fn QColor QColor::convertTo(Spec colorSpec) const
Creates a copy of \e this color in the format specified by \a colorSpec.
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 1851734bbc..52a6b5d211 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -255,7 +255,7 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *
Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>();
for (int i = 0; i < count; ++i) {
- const uint color = INV_PREMUL(src[i]);
+ const uint color = qUnpremultiply(src[i]);
const uint red = ((color >> redRightShift) & redMask) << redShift<Format>();
const uint green = ((color >> greenRightShift) & greenMask) << greenShift<Format>();
const uint blue = ((color >> blueRightShift) & blueMask) << blueShift<Format>();
@@ -387,7 +387,7 @@ static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src,
red = (red << redLeftShift) | (red >> redRightShift);
green = (green << greenLeftShift) | (green >> greenRightShift);
blue = (blue << blueLeftShift) | (blue >> blueRightShift);
- buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue);
+ buffer[i] = qPremultiply((alpha << 24) | (red << 16) | (green << 8) | blue);
}
}
return buffer;
@@ -446,7 +446,7 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src
if (!layout->premultiplied) {
for (int i = 0; i < count; ++i)
- buffer[i] = INV_PREMUL(src[i]);
+ buffer[i] = qUnpremultiply(src[i]);
src = buffer;
}
for (int i = 0; i < count; ++i) {
@@ -505,7 +505,7 @@ static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i]));
+ buffer[i] = qConvertRgb32To16(qUnpremultiply(src[i]));
return buffer;
}
#endif
@@ -515,7 +515,7 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *clut)
{
for (int i = 0; i < count; ++i)
- buffer[i] = PREMUL(clut[src[i]]);
+ buffer[i] = qPremultiply(clut[src[i]]);
return buffer;
}
@@ -529,7 +529,7 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = PREMUL(src[i]);
+ buffer[i] = qPremultiply(src[i]);
return buffer;
}
@@ -545,7 +545,7 @@ static const uint *QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, const uin
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = PREMUL(RGBA2ARGB(src[i]));
+ buffer[i] = qPremultiply(RGBA2ARGB(src[i]));
return buffer;
}
@@ -553,7 +553,7 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = INV_PREMUL(src[i]);
+ buffer[i] = qUnpremultiply(src[i]);
return buffer;
}
@@ -569,7 +569,7 @@ static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const u
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = ARGB2RGBA(INV_PREMUL(src[i]));
+ buffer[i] = ARGB2RGBA(qUnpremultiply(src[i]));
return buffer;
}
@@ -585,7 +585,7 @@ static const uint *QT_FASTCALL convertRGBXFromARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = ARGB2RGBA(0xff000000 | INV_PREMUL(src[i]));
+ buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i]));
return buffer;
}
@@ -853,9 +853,9 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
*/
static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
{
- QRgb color_0 = PREMUL(rbuf->destColor0);
- QRgb color_1 = PREMUL(rbuf->destColor1);
- color = PREMUL(color);
+ QRgb color_0 = qPremultiply(rbuf->destColor0);
+ QRgb color_1 = qPremultiply(rbuf->destColor1);
+ color = qPremultiply(color);
int r = qRed(color);
int g = qGreen(color);
@@ -6250,7 +6250,7 @@ static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer,
quint32 color)
{
qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
- INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
+ qUnpremultiply(color), x, y, width, height, rasterBuffer->bytesPerLine());
}
static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer,
@@ -6266,7 +6266,7 @@ static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer,
quint32 color)
{
qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
- ARGB2RGBA(INV_PREMUL(color)), x, y, width, height, rasterBuffer->bytesPerLine());
+ ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine());
}
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 0f98b07229..bbeb73f0af 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -599,14 +599,6 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
return (uint(t)) | (uint(t >> 24));
}
-static Q_ALWAYS_INLINE uint PREMUL(uint x) {
- uint a = x >> 24;
- quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
- t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
- t &= 0x000000ff00ff00ff;
- return (uint(t)) | (uint(t >> 24)) | (a << 24);
-}
-
#else // 32-bit versions
static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
@@ -639,20 +631,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
# pragma pop
#endif
-static Q_ALWAYS_INLINE uint PREMUL(uint x) {
- uint a = x >> 24;
- uint t = (x & 0xff00ff) * a;
- t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
- t &= 0xff00ff;
-
- x = ((x >> 8) & 0xff) * a;
- x = (x + ((x >> 8) & 0xff) + 0x80);
- x &= 0xff00;
- x |= t | (a << 24);
- return x;
-}
#endif
+
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) {
quint32 rgb = x >> 8;
@@ -691,17 +672,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) {
return t;
}
-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;
- // We add 0x8000 to get even rounding. The rounding also ensures that PREMUL(INV_PREMUL(p)) == p for all p.
- return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha);
-}
+// FIXME: Remove when all Qt modules have stopped using PREMUL and INV_PREMUL
+#define PREMUL(x) qPremultiply(x)
+#define INV_PREMUL(p) qUnpremultiply(p)
struct quint24 {
quint24(uint value);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bdd0d9cd4c..9a2e49618c 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1823,7 +1823,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
- d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
+ d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
if ((d->solid_color_filler.solid.color & 0xff000000) == 0
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
return;
@@ -2272,7 +2272,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
| ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
break;
default:
- d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
+ d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color, s->intOpacity));
break;
}
@@ -3662,7 +3662,7 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
- QRgb fg = PREMUL(color.rgba());
+ QRgb fg = qPremultiply(color.rgba());
QRgb bg = 0;
int height = sourceImage.height();
@@ -3702,8 +3702,8 @@ QImage::Format QRasterBuffer::prepare(QImage *image)
drawHelper = qDrawHelper + format;
if (image->depth() == 1 && image->colorTable().size() == 2) {
monoDestinationWithClut = true;
- destColor0 = PREMUL(image->colorTable()[0]);
- destColor1 = PREMUL(image->colorTable()[1]);
+ destColor0 = qPremultiply(image->colorTable()[0]);
+ destColor1 = qPremultiply(image->colorTable()[1]);
}
return format;
@@ -4260,8 +4260,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
}
if (colorInterpolation) {
- first_color = PREMUL(first_color);
- second_color = PREMUL(second_color);
+ first_color = qPremultiply(first_color);
+ second_color = qPremultiply(second_color);
}
int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
@@ -4282,7 +4282,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = first_color;
else
- colorTable[i] = PREMUL(first_color);
+ colorTable[i] = qPremultiply(first_color);
}
if (i < second_index) {
@@ -4311,7 +4311,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = color;
else
- colorTable[i] = PREMUL(color);
+ colorTable[i] = qPremultiply(color);
}
}
@@ -4319,7 +4319,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = second_color;
else
- colorTable[i] = PREMUL(second_color);
+ colorTable[i] = qPremultiply(second_color);
}
return;
@@ -4327,7 +4327,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
if (stopCount == 1) {
- current_color = PREMUL(current_color);
+ current_color = qPremultiply(current_color);
for (int i = 0; i < size; ++i)
colorTable[i] = current_color;
return;
@@ -4344,7 +4344,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
// Up to first point
- colorTable[pos++] = PREMUL(current_color);
+ colorTable[pos++] = qPremultiply(current_color);
while (dpos <= begin_pos) {
colorTable[pos] = colorTable[pos - 1];
++pos;
@@ -4366,8 +4366,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
if (colorInterpolation) {
- current_color = PREMUL(current_color);
- next_color = PREMUL(next_color);
+ current_color = qPremultiply(current_color);
+ next_color = qPremultiply(next_color);
}
qreal diff = stops[current_stop+1].first - stops[current_stop].first;
@@ -4384,7 +4384,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
else
- colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
+ colorTable[pos] = qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
++pos;
dpos += incr;
@@ -4408,8 +4408,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation) {
if (skip != 1)
- current_color = PREMUL(current_color);
- next_color = PREMUL(next_color);
+ current_color = qPremultiply(current_color);
+ next_color = qPremultiply(next_color);
}
qreal diff = stops[current_stop+1].first - stops[current_stop].first;
@@ -4421,7 +4421,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
}
// After last point
- current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
+ current_color = qPremultiply(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
while (pos < size - 1) {
colorTable[pos] = current_color;
++pos;
@@ -4455,7 +4455,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
type = Solid;
QColor c = qbrush_color(brush);
QRgb rgba = c.rgba();
- solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
+ solid.color = qPremultiply(ARGB_COMBINE_ALPHA(rgba, alpha));
if ((solid.color & 0xff000000) == 0
&& compositionMode == QPainter::CompositionMode_SourceOver) {
type = None;
diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h
index 3c2bc5b97a..d8e19302d1 100644
--- a/src/gui/painting/qrgb.h
+++ b/src/gui/painting/qrgb.h
@@ -43,6 +43,7 @@
#define QRGB_H
#include <QtCore/qglobal.h>
+#include <QtCore/qprocessordetection.h>
QT_BEGIN_NAMESPACE
@@ -79,6 +80,48 @@ inline Q_DECL_CONSTEXPR int qGray(QRgb rgb) // convert RGB to gra
inline Q_DECL_CONSTEXPR bool qIsGray(QRgb rgb)
{ return qRed(rgb) == qGreen(rgb) && qRed(rgb) == qBlue(rgb); }
+
+#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit version
+inline QRgb qPremultiply(QRgb x)
+{
+ const uint a = qAlpha(x);
+ quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
+ t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
+ t &= 0x000000ff00ff00ff;
+ return (uint(t)) | (uint(t >> 24)) | (a << 24);
+}
+#else // 32-bit version
+inline QRgb qPremultiply(QRgb x)
+{
+ const uint a = qAlpha(x);
+ uint t = (x & 0xff00ff) * a;
+ t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
+ t &= 0xff00ff;
+
+ x = ((x >> 8) & 0xff) * a;
+ x = (x + ((x >> 8) & 0xff) + 0x80);
+ x &= 0xff00;
+ x |= t | (a << 24);
+ return x;
+}
+#endif
+
+Q_GUI_EXPORT extern const uint qt_inv_premul_factor[];
+
+inline QRgb qUnpremultiply(QRgb p)
+{
+ const uint alpha = qAlpha(p);
+ // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut.
+ 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 = qt_inv_premul_factor[alpha];
+ // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p.
+ return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha);
+}
+
QT_END_NAMESPACE
#endif // QRGB_H