summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Brooks <special@dereferenced.net>2010-07-05 19:17:49 (GMT)
committerBenjamin Poulain <benjamin.poulain@nokia.com>2010-07-07 09:57:10 (GMT)
commitdad8e33546a209820da1f3d07a0e331e001bc23e (patch)
tree4312cf786a880196e9658df45ee7b1826fbbaa1f /src
parent93bcbe213e947843184a75f4b237c8dff45ca866 (diff)
downloadQt-dad8e33546a209820da1f3d07a0e331e001bc23e.zip
Qt-dad8e33546a209820da1f3d07a0e331e001bc23e.tar.gz
Qt-dad8e33546a209820da1f3d07a0e331e001bc23e.tar.bz2
SSE2 implementation of convert_ARGB_to_ARGB_PM_inplace for QImage
Merge-request: 725 Reviewed-by: Benjamin Poulain <benjamin.poulain@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/tools/qsimd_p.h5
-rw-r--r--src/gui/image/image.pri3
-rw-r--r--src/gui/image/qimage.cpp18
-rw-r--r--src/gui/image/qimage_p.h2
-rw-r--r--src/gui/image/qimage_sse2.cpp109
-rw-r--r--src/gui/kernel/qapplication.cpp3
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp12
-rw-r--r--src/gui/painting/qdrawingprimitive_sse2_p.h6
8 files changed, 144 insertions, 14 deletions
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index 58d2dcb..0ed9d5d 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -58,8 +58,7 @@ QT_BEGIN_HEADER
#endif
// SSE intrinsics
-#if defined(QT_HAVE_SSE2) && !defined(QT_BOOTSTRAPPED) && (defined(__SSE2__) \
- || (defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP == 2)))
+#if defined(QT_HAVE_SSE2) && (defined(__SSE2__) || defined(Q_CC_MSVC))
#if defined(QT_LINUXBASE)
/// this is an evil hack - the posix_memalign declaration in LSB
/// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431
@@ -73,8 +72,10 @@ QT_BEGIN_HEADER
# include <emmintrin.h>
#endif
+#if !defined(QT_BOOTSTRAPPED) && (!defined(Q_CC_MSVC) || (defined(_M_X64) || _M_IX86_FP == 2))
#define QT_ALWAYS_HAVE_SSE2
#endif
+#endif // defined(QT_HAVE_SSE2) && (defined(__SSE2__) || defined(Q_CC_MSVC))
// NEON intrinsics
#if defined(QT_HAVE_NEON)
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 9f0c87e..3a02d56 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -92,3 +92,6 @@ contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri)
contains(QT_CONFIG, mng):include($$PWD/qmnghandler.pri)
contains(QT_CONFIG, tiff):include($$PWD/qtiffhandler.pri)
contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri)
+
+# SIMD
+SSE2_SOURCES += image/qimage_sse2.cpp
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 79f266d..88a0366 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -58,6 +58,7 @@
#include <private/qmemrotate_p.h>
#include <private/qpixmapdata_p.h>
#include <private/qimagescale_p.h>
+#include <private/qsimd_p.h>
#include <qhash.h>
@@ -209,7 +210,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu
break;
}
- const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 8)
+ const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4)
// sanity check for potential overflows
if (INT_MAX/depth < width
@@ -3630,7 +3631,7 @@ static const Image_Converter converter_map[QImage::NImageFormats][QImage::NImage
} // Format_ARGB4444_Premultiplied
};
-static const InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
+static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -3727,6 +3728,19 @@ static const InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats
} // Format_ARGB4444_Premultiplied
};
+void qInitImageConversions()
+{
+ const uint features = qDetectCPUFeatures();
+ Q_UNUSED(features);
+
+#ifdef QT_HAVE_SSE2
+ if (features & SSE2) {
+ extern bool convert_ARGB_to_ARGB_PM_inplace_SSE2(QImageData *data, Qt::ImageConversionFlags);
+ inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_SSE2;
+ }
+#endif
+}
+
/*!
Returns a copy of the image in the given \a format.
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index f1a0c47..5272848 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -108,6 +108,8 @@ struct Q_GUI_EXPORT QImageData { // internal image data
QPaintEngine *paintEngine;
};
+void qInitImageConversions();
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp
new file mode 100644
index 0000000..e2b89b9
--- /dev/null
+++ b/src/gui/image/qimage_sse2.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qimage.h"
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+#include <private/qdrawhelper_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
+
+#ifdef QT_HAVE_SSE2
+
+QT_BEGIN_NAMESPACE
+
+bool convert_ARGB_to_ARGB_PM_inplace_SSE2(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_ARGB32);
+
+ // extra pixels on each line
+ const int spare = data->width & 3;
+ // width in pixels of the pad at the end of each line
+ const int pad = (data->bytes_per_line >> 2) - data->width;
+ const int iter = data->width >> 2;
+ int height = data->height;
+
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i nullVector = _mm_setzero_si128();
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ __m128i *d = reinterpret_cast<__m128i*>(data->data);
+ while (height--) {
+ const __m128i *end = d + iter;
+
+ for (; d != end; ++d) {
+ const __m128i srcVector = _mm_loadu_si128(d);
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) {
+ // opaque, data is unchanged
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) == 0xffff) {
+ // fully transparent
+ _mm_storeu_si128(d, nullVector);
+ } else {
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
+
+ __m128i result;
+ BYTE_MUL_SSE2(result, srcVector, alphaChannel, colorMask, half);
+ result = _mm_or_si128(_mm_andnot_si128(alphaMask, result), srcVectorAlpha);
+ _mm_storeu_si128(d, result);
+ }
+ }
+
+ QRgb *p = reinterpret_cast<QRgb*>(d);
+ QRgb *pe = p+spare;
+ for (; p != pe; ++p) {
+ if (*p < 0x00ffffff)
+ *p = 0;
+ else if (*p < 0xff000000)
+ *p = PREMUL(*p);
+ }
+
+ d = reinterpret_cast<__m128i*>(p+pad);
+ }
+
+ data->format = QImage::Format_ARGB32_Premultiplied;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSE2
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index ccfe88c..94211fd 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -902,6 +902,7 @@ QApplication::QApplication(Display *dpy, int &argc, char **argv,
#endif // Q_WS_X11
extern void qInitDrawhelperAsm();
+extern void qInitImageConversions();
extern int qRegisterGuiVariant();
extern int qUnregisterGuiVariant();
#ifndef QT_NO_STATEMACHINE
@@ -959,6 +960,8 @@ void QApplicationPrivate::initialize()
// Set up which span functions should be used in raster engine...
qInitDrawhelperAsm();
+ // and QImage conversion functions
+ qInitImageConversions();
#ifndef QT_NO_WHEELEVENT
QApplicationPrivate::wheel_scroll_lines = 3;
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index ae16fed..346e177 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -43,18 +43,10 @@
#ifdef QT_HAVE_SSE2
+#include <private/qsimd_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
#include <private/qpaintengine_raster_p.h>
-#ifdef QT_LINUXBASE
-// this is an evil hack - the posix_memalign declaration in LSB
-// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431
-# define posix_memalign _lsb_hack_posix_memalign
-# include <emmintrin.h>
-# undef posix_memalign
-#else
-# include <emmintrin.h>
-#endif
-
QT_BEGIN_NAMESPACE
void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h
index 2b595c5..3c96946 100644
--- a/src/gui/painting/qdrawingprimitive_sse2_p.h
+++ b/src/gui/painting/qdrawingprimitive_sse2_p.h
@@ -42,6 +42,10 @@
#ifndef QDRAWINGPRIMITIVE_SSE2_P_H
#define QDRAWINGPRIMITIVE_SSE2_P_H
+#include <private/qsimd_p.h>
+
+#ifdef QT_HAVE_SSE2
+
//
// W A R N I N G
// -------------
@@ -213,4 +217,6 @@ QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
+#endif // QT_HAVE_SSE2
+
#endif // QDRAWINGPRIMITIVE_SSE2_P_H