diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 6ddfcdfaf4..23c8e42ded 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -174,29 +174,31 @@ template static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - Q_CONSTEXPR uint redMask = ((1 << redWidth()) - 1); - Q_CONSTEXPR uint greenMask = ((1 << greenWidth()) - 1); - Q_CONSTEXPR uint blueMask = ((1 << blueWidth()) - 1); + auto conversion = [](uint s) { + // MSVC needs these constexpr defined in here otherwise it will create a capture. + Q_CONSTEXPR uint redMask = ((1 << redWidth()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth()) - 1); - Q_CONSTEXPR uchar redLeftShift = 8 - redWidth(); - Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth(); - Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth(); - Q_CONSTEXPR uchar redRightShift = 2 * redWidth() - 8; - Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth() - 8; - Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth() - 8; - for (int i = 0; i < count; ++i) { - uint red = (src[i] >> redShift()) & redMask; - uint green = (src[i] >> greenShift()) & greenMask; - uint blue = (src[i] >> blueShift()) & blueMask; + uint red = (s >> redShift()) & redMask; + uint green = (s >> greenShift()) & greenMask; + uint blue = (s >> blueShift()) & blueMask; red = ((red << redLeftShift) | (red >> redRightShift)) << 16; green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; blue = (blue << blueLeftShift) | (blue >> blueRightShift); - buffer[i] = 0xff000000 | red | green | blue; - } + return 0xff000000 | red | green | blue; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); return buffer; } @@ -348,21 +350,21 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint * // RGB32 -> RGB888 is not a precision loss. if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) { - Q_CONSTEXPR uint rMask = (1 << rWidth) - 1; - Q_CONSTEXPR uint gMask = (1 << gWidth) - 1; - Q_CONSTEXPR uint bMask = (1 << bWidth) - 1; + auto conversion = [](uint s) { + const uint c = fromRGB ? s : qUnpremultiply(s); + Q_CONSTEXPR uint rMask = (1 << redWidth()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth()) - 1; + Q_CONSTEXPR uchar rRightShift = 24 - redWidth(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth(); - Q_CONSTEXPR uchar rRightShift = 24 - rWidth; - Q_CONSTEXPR uchar gRightShift = 16 - gWidth; - Q_CONSTEXPR uchar bRightShift = 8 - bWidth; - - for (int i = 0; i < count; ++i) { - const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); const uint r = ((c >> rRightShift) & rMask) << redShift(); const uint g = ((c >> gRightShift) & gMask) << greenShift(); const uint b = ((c >> bRightShift) & bMask) << blueShift(); - buffer[i] = r | g | b; - } + return r | g | b; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); } else { // We do ordered dither by using a rounding conversion, but instead of // adding half of input precision, we add the adjusted result from the @@ -394,32 +396,32 @@ template static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *dither) { - Q_CONSTEXPR uchar aWidth = alphaWidth(); - Q_CONSTEXPR uchar rWidth = redWidth(); - Q_CONSTEXPR uchar gWidth = greenWidth(); - Q_CONSTEXPR uchar bWidth = blueWidth(); - if (!dither) { - Q_CONSTEXPR uint aMask = (1 << aWidth) - 1; - Q_CONSTEXPR uint rMask = (1 << rWidth) - 1; - Q_CONSTEXPR uint gMask = (1 << gWidth) - 1; - Q_CONSTEXPR uint bMask = (1 << bWidth) - 1; + auto conversion = [](uint c) { + Q_CONSTEXPR uint aMask = (1 << alphaWidth()) - 1; + Q_CONSTEXPR uint rMask = (1 << redWidth()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth()) - 1; - Q_CONSTEXPR uchar aRightShift = 32 - aWidth; - Q_CONSTEXPR uchar rRightShift = 24 - rWidth; - Q_CONSTEXPR uchar gRightShift = 16 - gWidth; - Q_CONSTEXPR uchar bRightShift = 8 - bWidth; + Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth(); + Q_CONSTEXPR uchar rRightShift = 24 - redWidth(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth(); - Q_CONSTEXPR uint aOpaque = aMask << alphaShift(); - for (int i = 0; i < count; ++i) { - const uint c = src[i]; + Q_CONSTEXPR uint aOpaque = aMask << alphaShift(); const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift()); const uint r = ((c >> rRightShift) & rMask) << redShift(); const uint g = ((c >> gRightShift) & gMask) << greenShift(); const uint b = ((c >> bRightShift) & bMask) << blueShift(); - buffer[i] = a | r | g | b; - } + return a | r | g | b; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); } else { + Q_CONSTEXPR uchar aWidth = alphaWidth(); + Q_CONSTEXPR uchar rWidth = redWidth(); + Q_CONSTEXPR uchar gWidth = greenWidth(); + Q_CONSTEXPR uchar bWidth = blueWidth(); + const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; for (int i = 0; i < count; ++i) { const uint c = src[i]; @@ -514,8 +516,7 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint static const uint *QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = RGBA2ARGB(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, RGBA2ARGB); return buffer; } @@ -568,8 +569,7 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, ARGB2RGBA); return buffer; } @@ -695,8 +695,7 @@ static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const u static const uint *QT_FASTCALL convertRGBXFromRGB32(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); }); return buffer; } @@ -713,8 +712,7 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui const QVector *, QDitherInfo *dither) { if (!dither) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertA2rgb30ToArgb32(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32); } else { for (int i = 0; i < count; ++i) { const uint c = src[i]; @@ -796,8 +794,7 @@ template static const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertArgb32ToA2rgb30(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertArgb32ToA2rgb30); return buffer; } @@ -814,8 +811,7 @@ template static const uint *QT_FASTCALL convertRGB30FromARGB32PM(uint *buffer, const uint *src, int count, const QVector *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertRgb32ToRgb30(qUnpremultiply(src[i])); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertRgb32ToRgb30); return buffer; } diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 4c2fe87355..ebf215a3eb 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -1104,22 +1104,30 @@ inline int qBlue565(quint16 rgb) { return (b << 3) | (b >> 2); } +// We manually unalias the variables to make sure the compiler +// fully optimizes both aliased and unaliased cases. +#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \ + if (src == buffer) { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(buffer[i]); \ + } else { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(src[i]); \ + } + static Q_ALWAYS_INLINE const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count) { - for (int i = 0; i < count; ++i) - buffer[i] = qPremultiply(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply); return buffer; } static Q_ALWAYS_INLINE const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count) { - for (int i = 0; i < count; ++i) - buffer[i] = qPremultiply(RGBA2ARGB(src[i])); + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));}); return buffer; } - const uint qt_bayer_matrix[16][16] = { { 0x1, 0xc0, 0x30, 0xf0, 0xc, 0xcc, 0x3c, 0xfc, 0x3, 0xc3, 0x33, 0xf3, 0xf, 0xcf, 0x3f, 0xff},