diff options
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/painting.pri | 5 | ||||
-rw-r--r-- | src/gui/painting/qcoregraphics.mm | 566 | ||||
-rw-r--r-- | src/gui/painting/qcoregraphics_p.h | 121 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 683 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_avx2.cpp | 305 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_p.h | 5 |
6 files changed, 1159 insertions, 526 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index c47060a2ad..a61865a0b6 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -99,6 +99,11 @@ SOURCES += \ painting/qplatformbackingstore.cpp \ painting/qpathsimplifier.cpp +darwin { + HEADERS += painting/qcoregraphics_p.h + SOURCES += painting/qcoregraphics.mm +} + SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm new file mode 100644 index 0000000000..a29d60ca6e --- /dev/null +++ b/src/gui/painting/qcoregraphics.mm @@ -0,0 +1,566 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoregraphics_p.h" + +#include <private/qcore_mac_p.h> +#include <qpa/qplatformpixmap.h> +#include <QtGui/qicon.h> +#include <QtGui/private/qpaintengine_p.h> +#include <QtCore/qdebug.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qoperatingsystemversion.h> + +QT_BEGIN_NAMESPACE + +// ---------------------- Images ---------------------- + +CGImageRef qt_mac_toCGImage(const QImage &inImage) +{ + CGImageRef cgImage = inImage.toCGImage(); + if (cgImage) + return cgImage; + + // Convert image data to a known-good format if the fast conversion fails. + return inImage.convertToFormat(QImage::Format_ARGB32_Premultiplied).toCGImage(); +} + +CGImageRef qt_mac_toCGImageMask(const QImage &image) +{ + static const auto deleter = [](void *image, const void *, size_t) { delete static_cast<QImage *>(image); }; + QCFType<CGDataProviderRef> dataProvider = + CGDataProviderCreateWithData(new QImage(image), image.bits(), + image.byteCount(), deleter); + + return CGImageMaskCreate(image.width(), image.height(), 8, image.depth(), + image.bytesPerLine(), dataProvider, NULL, false); +} + +OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage) +{ + // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev) + OSStatus err = noErr; + +#ifdef Q_OS_MACOS + require_action(inContext != NULL, InvalidContext, err = paramErr); + require_action(inBounds != NULL, InvalidBounds, err = paramErr); + require_action(inImage != NULL, InvalidImage, err = paramErr); +#endif + + CGContextSaveGState( inContext ); + CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds)); + CGContextScaleCTM(inContext, 1, -1); + + CGContextDrawImage(inContext, *inBounds, inImage); + + CGContextRestoreGState(inContext); + +#ifdef Q_OS_MACOS +InvalidImage: +InvalidBounds: +InvalidContext: +#endif + return err; +} + +QImage qt_mac_toQImage(CGImageRef image) +{ + const size_t w = CGImageGetWidth(image), + h = CGImageGetHeight(image); + QImage ret(w, h, QImage::Format_ARGB32_Premultiplied); + ret.fill(Qt::transparent); + CGRect rect = CGRectMake(0, 0, w, h); + QMacCGContext ctx(&ret); + qt_mac_drawCGImage(ctx, &rect, image); + return ret; +} + +#ifdef Q_OS_MACOS + +QT_END_NAMESPACE + +@interface NSGraphicsContext (QtAdditions) + ++ (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState; + +@end + +@implementation NSGraphicsContext (QtAdditions) + ++ (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState +{ +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_NA) + if (QT_PREPEND_NAMESPACE(QOperatingSystemVersion::current()) >= QT_PREPEND_NAMESPACE(QOperatingSystemVersion::OSXYosemite)) + return [self graphicsContextWithCGContext:graphicsPort flipped:initialFlippedState]; +#endif + return [self graphicsContextWithGraphicsPort:graphicsPort flipped:initialFlippedState]; +} + +@end + +QT_BEGIN_NAMESPACE + +static NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) +{ + NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; + return newImage; +} + +NSImage *qt_mac_create_nsimage(const QPixmap &pm) +{ + if (pm.isNull()) + return 0; + QImage image = pm.toImage(); + CGImageRef cgImage = qt_mac_toCGImage(image); + NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage); + CGImageRelease(cgImage); + return nsImage; +} + +NSImage *qt_mac_create_nsimage(const QIcon &icon) +{ + if (icon.isNull()) + return nil; + + NSImage *nsImage = [[NSImage alloc] init]; + foreach (QSize size, icon.availableSizes()) { + QPixmap pm = icon.pixmap(size); + QImage image = pm.toImage(); + CGImageRef cgImage = qt_mac_toCGImage(image); + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + [nsImage addRepresentation:imageRep]; + [imageRep release]; + CGImageRelease(cgImage); + } + return nsImage; +} + +QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size) +{ + const NSSize pixmapSize = NSMakeSize(size.width(), size.height()); + QPixmap pixmap(pixmapSize.width, pixmapSize.height); + pixmap.fill(Qt::transparent); + [image setSize:pixmapSize]; + const NSRect iconRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height); + QMacCGContext ctx(&pixmap); + if (!ctx) + return QPixmap(); + NSGraphicsContext *gc = [NSGraphicsContext qt_graphicsContextWithCGContext:ctx flipped:YES]; + if (!gc) + return QPixmap(); + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:gc]; + [image drawInRect:iconRect fromRect:iconRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil]; + [NSGraphicsContext restoreGraphicsState]; + return pixmap; +} + +#endif // Q_OS_MACOS + +// ---------------------- Colors and Brushes ---------------------- + +QColor qt_mac_toQColor(CGColorRef color) +{ + QColor qtColor; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); + const CGFloat *components = CGColorGetComponents(color); + if (model == kCGColorSpaceModelRGB) { + qtColor.setRgbF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelCMYK) { + qtColor.setCmykF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelMonochrome) { + qtColor.setRgbF(components[0], components[0], components[0], components[1]); + } else { + // Colorspace we can't deal with. + qWarning("Qt: qt_mac_toQColor: cannot convert from colorspace model: %d", model); + Q_ASSERT(false); + } + return qtColor; +} + +#ifdef Q_OS_MACOS +QColor qt_mac_toQColor(const NSColor *color) +{ + QColor qtColor; + NSString *colorSpace = [color colorSpaceName]; + if (colorSpace == NSDeviceCMYKColorSpace) { + CGFloat cyan, magenta, yellow, black, alpha; + [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha]; + qtColor.setCmykF(cyan, magenta, yellow, black, alpha); + } else { + NSColor *tmpColor; + tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + CGFloat red, green, blue, alpha; + [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; + qtColor.setRgbF(red, green, blue, alpha); + } + return qtColor; +} +#endif + +QBrush qt_mac_toQBrush(CGColorRef color) +{ + QBrush qtBrush; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); + if (model == kCGColorSpaceModelPattern) { + // Colorspace we can't deal with; the color is drawn directly using a callback. + qWarning("Qt: qt_mac_toQBrush: cannot convert from colorspace model: %d", model); + Q_ASSERT(false); + } else { + qtBrush.setStyle(Qt::SolidPattern); + qtBrush.setColor(qt_mac_toQColor(color)); + } + return qtBrush; +} + +#ifdef Q_OS_MACOS +static bool qt_mac_isSystemColorOrInstance(const NSColor *color, NSString *colorNameComponent, NSString *className) +{ + // We specifically do not want isKindOfClass: here + if ([color.className isEqualToString:className]) // NSPatternColorSpace + return true; + if ([color.catalogNameComponent isEqualToString:@"System"] && + [color.colorNameComponent isEqualToString:colorNameComponent] && + [color.colorSpaceName isEqualToString:NSNamedColorSpace]) + return true; + return false; +} + +QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup) +{ + QBrush qtBrush; + + // QTBUG-49773: This calls NSDrawMenuItemBackground to render a 1 by n gradient; could use HITheme + if ([color.className isEqualToString:@"NSMenuItemHighlightColor"]) { + qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMenuItemHighlightColor"); + return qtBrush; + } + + // Not a catalog color or a manifestation of System.windowBackgroundColor; + // only retrieved from NSWindow.backgroundColor directly + if ([color.className isEqualToString:@"NSMetalPatternColor"]) { + // NSTexturedBackgroundWindowMask, could theoretically handle this without private API by + // creating a window with the appropriate properties and then calling NSWindow.backgroundColor.patternImage, + // which returns a texture sized 1 by (window height, including frame), backed by a CGPattern + // which follows the window key state... probably need to allow QBrush to store a function pointer + // like CGPattern does + qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMetalPatternColor"); + return qtBrush; + } + + // No public API to get these colors/stops; + // both accurately obtained through runtime object inspection on OS X 10.11 + // (the NSColor object has NSGradient i-vars for both color groups) + if (qt_mac_isSystemColorOrInstance(color, @"_sourceListBackgroundColor", @"NSSourceListBackgroundColor")) { + QLinearGradient gradient; + if (colorGroup == QPalette::Active) { + gradient.setColorAt(0, QColor(233, 237, 242)); + gradient.setColorAt(0.5, QColor(225, 229, 235)); + gradient.setColorAt(1, QColor(209, 216, 224)); + } else { + gradient.setColorAt(0, QColor(248, 248, 248)); + gradient.setColorAt(0.5, QColor(240, 240, 240)); + gradient.setColorAt(1, QColor(235, 235, 235)); + } + return QBrush(gradient); + } + + // A couple colors are special... they are actually instances of NSGradientPatternColor, which + // override set/setFill/setStroke to instead initialize an internal color + // ([NSColor colorWithCalibratedWhite:0.909804 alpha:1.000000]) while still returning the + // ruled lines pattern image (from OS X 10.4) to the user from -[NSColor patternImage] + // (and providing no public API to get the underlying color without this insanity) + if (qt_mac_isSystemColorOrInstance(color, @"controlColor", @"NSGradientPatternColor") || + qt_mac_isSystemColorOrInstance(color, @"windowBackgroundColor", @"NSGradientPatternColor")) { + qtBrush.setStyle(Qt::SolidPattern); + qtBrush.setColor(qt_mac_toQColor(color.CGColor)); + return qtBrush; + } + + if (NSColor *patternColor = [color colorUsingColorSpaceName:NSPatternColorSpace]) { + NSImage *patternImage = patternColor.patternImage; + const QSizeF sz(patternImage.size.width, patternImage.size.height); + // FIXME: QBrush is not resolution independent (QTBUG-49774) + qtBrush.setTexture(qt_mac_toQPixmap(patternImage, sz)); + } else { + qtBrush.setStyle(Qt::SolidPattern); + qtBrush.setColor(qt_mac_toQColor(color)); + } + return qtBrush; +} +#endif + +// ---------------------- Color Management ---------------------- + +static CGColorSpaceRef m_genericColorSpace = 0; +static QHash<uint32_t, CGColorSpaceRef> m_displayColorSpaceHash; +static bool m_postRoutineRegistered = false; + +static void qt_mac_cleanUpMacColorSpaces() +{ + if (m_genericColorSpace) { + CFRelease(m_genericColorSpace); + m_genericColorSpace = 0; + } + QHash<uint32_t, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin(); + while (it != m_displayColorSpaceHash.constEnd()) { + if (it.value()) + CFRelease(it.value()); + ++it; + } + m_displayColorSpaceHash.clear(); +} + +static CGColorSpaceRef qt_mac_displayColorSpace(const QWindow *window) +{ + CGColorSpaceRef colorSpace = 0; + uint32_t displayID = 0; + +#ifdef Q_OS_MACOS + if (window == 0) { + displayID = CGMainDisplayID(); + } else { + displayID = CGMainDisplayID(); + /* + ### get correct display + const QRect &qrect = window->geometry(); + CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); + CGDisplayCount throwAway; + CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); + if (dErr != kCGErrorSuccess) + return macDisplayColorSpace(0); // fall back on main display + */ + } + if ((colorSpace = m_displayColorSpaceHash.value(displayID))) + return colorSpace; + + colorSpace = CGDisplayCopyColorSpace(displayID); +#else + Q_UNUSED(window); +#endif + + if (colorSpace == 0) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + m_displayColorSpaceHash.insert(displayID, colorSpace); + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); + } + return colorSpace; +} + +CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) +{ + Q_UNUSED(paintDevice); + + // FIXME: Move logic into each paint device once Qt has support for color spaces + return qt_mac_displayColorSpace(0); + + // The following code seems to take care of QWidget, but in reality doesn't, as + // qt_mac_displayColorSpace ignores the argument and always uses the main display. +#if 0 + bool isWidget = (paintDevice->devType() == QInternal::Widget); + return qt_mac_displayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice)->window() : 0); +#endif +} + +CGColorSpaceRef qt_mac_genericColorSpace() +{ +#if 0 + if (!m_genericColorSpace) { + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { + m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + } else + { + m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); + } + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); + } + } + return m_genericColorSpace; +#else + // Just return the main display colorspace for the moment. + return qt_mac_displayColorSpace(0); +#endif +} + +// ---------------------- Geometry Helpers ---------------------- + +void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform) +{ + CGAffineTransform old_xform = CGAffineTransformIdentity; + if (orig_xform) { //setup xforms + old_xform = CGContextGetCTM(hd); + CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(hd, *orig_xform); + } + + //do the clipping + CGContextBeginPath(hd); + if (rgn.isEmpty()) { + CGContextAddRect(hd, CGRectMake(0, 0, 0, 0)); + } else { + for (const QRect &r : rgn) { + CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height()); + CGContextAddRect(hd, mac_r); + } + } + CGContextClip(hd); + + if (orig_xform) {//reset xforms + CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd))); + CGContextConcatCTM(hd, old_xform); + } +} + +// move to QRegion? +void qt_mac_scale_region(QRegion *region, qreal scaleFactor) +{ + if (!region || !region->rectCount()) + return; + + QVector<QRect> scaledRects; + scaledRects.reserve(region->rectCount()); + + for (const QRect &rect : *region) + scaledRects.append(QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor)); + + region->setRects(&scaledRects[0], scaledRects.count()); +} + +// ---------------------- QMacCGContext ---------------------- + +QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) +{ + // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. + QImage *image = 0; + if (paintDevice->devType() == QInternal::Image) { + image = static_cast<QImage *>(paintDevice); + } else if (paintDevice->devType() == QInternal::Pixmap) { + + const QPixmap *pm = static_cast<const QPixmap*>(paintDevice); + QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data(); + if (data && data->classId() == QPlatformPixmap::RasterClass) { + image = data->buffer(); + } else { + qDebug("QMacCGContext: Unsupported pixmap class"); + } + } else if (paintDevice->devType() == QInternal::Widget) { + // TODO test: image = static_cast<QImage *>(static_cast<const QWidget *>(paintDevice)->backingStore()->paintDevice()); + qDebug("QMacCGContext: not implemented: Widget class"); + } + + if (!image) + return; // Context type not supported. + + CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(paintDevice); + uint flags = kCGImageAlphaPremultipliedFirst; + flags |= kCGBitmapByteOrder32Host; + + context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); +} + +QMacCGContext::QMacCGContext(QPainter *painter) : context(0) +{ + QPaintEngine *paintEngine = painter->paintEngine(); + + // Handle the case of QMacPrintEngine, which has an internal QCoreGraphicsPaintEngine + while (QPaintEngine *aggregateEngine = QPaintEnginePrivate::get(paintEngine)->aggregateEngine()) + paintEngine = aggregateEngine; + + paintEngine->syncState(); + + if (Qt::HANDLE handle = QPaintEnginePrivate::get(paintEngine)->nativeHandle()) { + context = static_cast<CGContextRef>(handle); + return; + } + + int devType = painter->device()->devType(); + if (paintEngine->type() == QPaintEngine::Raster + && (devType == QInternal::Widget || + devType == QInternal::Pixmap || + devType == QInternal::Image)) { + + CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(paintEngine->paintDevice()); + uint flags = kCGImageAlphaPremultipliedFirst; +#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version + flags |= kCGBitmapByteOrder32Host; +#endif + const QImage *image = static_cast<const QImage *>(paintEngine->paintDevice()); + + context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + + // Invert y axis + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); + + const qreal devicePixelRatio = image->devicePixelRatio(); + + if (devType == QInternal::Widget) { + // Set the clip rect which is an intersection of the system clip + // and the painter clip. To make matters more interesting these + // are in device pixels and device-independent pixels, respectively. + QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels + QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels + + if (painter->hasClipping()) { + QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels + qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels + r.translate(native.dx(), native.dy()); + if (clip.isEmpty()) + clip = r; + else + clip &= r; + } + qt_mac_clip_cg(context, clip, 0); // clip in device pixels + + // Scale the context so that painting happens in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); + CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio); + } else { + // Scale to paint in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); + } + } else { + qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h new file mode 100644 index 0000000000..ab2579387e --- /dev/null +++ b/src/gui/painting/qcoregraphics_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREGRAPHICS_P_H +#define QCOREGRAPHICS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qtguiglobal_p.h> +#include <QtGui/qregion.h> +#include <QtGui/qpalette.h> + +#include <CoreGraphics/CoreGraphics.h> +#ifdef Q_OS_MACOS +#include <AppKit/AppKit.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_MACOS +Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QPixmap &pm); +Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QIcon &icon); +Q_GUI_EXPORT QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size); +#endif +Q_GUI_EXPORT CGImageRef qt_mac_toCGImage(const QImage &qImage); +Q_GUI_EXPORT CGImageRef qt_mac_toCGImageMask(const QImage &qImage); +Q_GUI_EXPORT QImage qt_mac_toQImage(CGImageRef image); + +Q_GUI_EXPORT OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage); + +Q_GUI_EXPORT CGColorSpaceRef qt_mac_genericColorSpace(); +Q_GUI_EXPORT CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice); + +Q_GUI_EXPORT void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform); + +#ifdef Q_OS_MACOS +Q_GUI_EXPORT QColor qt_mac_toQColor(const NSColor *color); +Q_GUI_EXPORT QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup = QPalette::Normal); +#endif +Q_GUI_EXPORT QColor qt_mac_toQColor(CGColorRef color); +Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color); + +class Q_GUI_EXPORT QMacCGContext +{ +public: + inline QMacCGContext() { context = 0; } + QMacCGContext(QPaintDevice *pdev); + QMacCGContext(QPainter *p); + inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) { + context = cg; + if (!takeOwnership) + CGContextRetain(context); + } + inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } + inline ~QMacCGContext() { + if (context) + CGContextRelease(context); + } + inline bool isNull() const { return context; } + inline operator CGContextRef() { return context; } + inline QMacCGContext &operator=(const QMacCGContext ©) { + if (context) + CGContextRelease(context); + context = copy.context; + CGContextRetain(context); + return *this; + } + inline QMacCGContext &operator=(CGContextRef cg) { + if (context) + CGContextRelease(context); + context = cg; + CGContextRetain(context); //we do not take ownership + return *this; + } + +private: + CGContextRef context; +}; + +QT_END_NAMESPACE + +#endif // QCOREGRAPHICS_P_H diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index c697aceaf3..c1a49b7d9a 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -3263,342 +3263,72 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co return buffer; } -static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { - // Untransformed - { - 0, // Invalid - fetchUntransformed, // Mono - fetchUntransformed, // MonoLsb - fetchUntransformed, // Indexed8 - fetchUntransformedARGB32PM, // RGB32 - fetchUntransformed, // ARGB32 - fetchUntransformedARGB32PM, // ARGB32_Premultiplied - fetchUntransformedRGB16, // RGB16 - fetchUntransformed, // ARGB8565_Premultiplied - fetchUntransformed, // RGB666 - fetchUntransformed, // ARGB6666_Premultiplied - fetchUntransformed, // RGB555 - fetchUntransformed, // ARGB8555_Premultiplied - fetchUntransformed, // RGB888 - fetchUntransformed, // RGB444 - fetchUntransformed, // ARGB4444_Premultiplied - fetchUntransformed, // RGBX8888 - fetchUntransformed, // RGBA8888 - fetchUntransformed, // RGBA8888_Premultiplied - fetchUntransformed, // Format_BGR30 - fetchUntransformed, // Format_A2BGR30_Premultiplied - fetchUntransformed, // Format_RGB30 - fetchUntransformed, // Format_A2RGB30_Premultiplied - fetchUntransformed, // Alpha8 - fetchUntransformed, // Grayscale8 - }, - // Tiled - { - 0, // Invalid - fetchUntransformed, // Mono - fetchUntransformed, // MonoLsb - fetchUntransformed, // Indexed8 - fetchUntransformedARGB32PM, // RGB32 - fetchUntransformed, // ARGB32 - fetchUntransformedARGB32PM, // ARGB32_Premultiplied - fetchUntransformedRGB16, // RGB16 - fetchUntransformed, // ARGB8565_Premultiplied - fetchUntransformed, // RGB666 - fetchUntransformed, // ARGB6666_Premultiplied - fetchUntransformed, // RGB555 - fetchUntransformed, // ARGB8555_Premultiplied - fetchUntransformed, // RGB888 - fetchUntransformed, // RGB444 - fetchUntransformed, // ARGB4444_Premultiplied - fetchUntransformed, // RGBX8888 - fetchUntransformed, // RGBA8888 - fetchUntransformed, // RGBA8888_Premultiplied - fetchUntransformed, // BGR30 - fetchUntransformed, // A2BGR30_Premultiplied - fetchUntransformed, // RGB30 - fetchUntransformed, // A2RGB30_Premultiplied - fetchUntransformed, // Alpha8 - fetchUntransformed, // Grayscale8 - }, - // Transformed - { - 0, // Invalid - fetchTransformed<BlendTransformed>, // Mono - fetchTransformed<BlendTransformed>, // MonoLsb - fetchTransformed<BlendTransformed>, // Indexed8 - fetchTransformedARGB32PM<BlendTransformed>, // RGB32 - fetchTransformed<BlendTransformed>, // ARGB32 - fetchTransformedARGB32PM<BlendTransformed>, // ARGB32_Premultiplied - fetchTransformed<BlendTransformed>, // RGB16 - fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied - fetchTransformed<BlendTransformed>, // RGB666 - fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied - fetchTransformed<BlendTransformed>, // RGB555 - fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied - fetchTransformed<BlendTransformed>, // RGB888 - fetchTransformed<BlendTransformed>, // RGB444 - fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied - fetchTransformed<BlendTransformed>, // RGBX8888 - fetchTransformed<BlendTransformed>, // RGBA8888 - fetchTransformed<BlendTransformed>, // RGBA8888_Premultiplied - fetchTransformed<BlendTransformed>, // BGR30 - fetchTransformed<BlendTransformed>, // A2BGR30_Premultiplied - fetchTransformed<BlendTransformed>, // RGB30 - fetchTransformed<BlendTransformed>, // A2RGB30_Premultiplied - fetchTransformed<BlendTransformed>, // Alpah8 - fetchTransformed<BlendTransformed>, // Grayscale8 - }, - { - 0, // TransformedTiled - fetchTransformed<BlendTransformedTiled>, // Mono - fetchTransformed<BlendTransformedTiled>, // MonoLsb - fetchTransformed<BlendTransformedTiled>, // Indexed8 - fetchTransformedARGB32PM<BlendTransformedTiled>, // RGB32 - fetchTransformed<BlendTransformedTiled>, // ARGB32 - fetchTransformedARGB32PM<BlendTransformedTiled>, // ARGB32_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGB16 - fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGB666 - fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGB555 - fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGB888 - fetchTransformed<BlendTransformedTiled>, // RGB444 - fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGBX8888 - fetchTransformed<BlendTransformedTiled>, // RGBA8888 - fetchTransformed<BlendTransformedTiled>, // RGBA8888_Premultiplied - fetchTransformed<BlendTransformedTiled>, // BGR30 - fetchTransformed<BlendTransformedTiled>, // A2BGR30_Premultiplied - fetchTransformed<BlendTransformedTiled>, // RGB30 - fetchTransformed<BlendTransformedTiled>, // A2RGB30_Premultiplied - fetchTransformed<BlendTransformedTiled>, // Alpha8 - fetchTransformed<BlendTransformedTiled>, // Grayscale8 - }, - { - 0, // Bilinear - fetchTransformedBilinear<BlendTransformedBilinear>, // Mono - fetchTransformedBilinear<BlendTransformedBilinear>, // MonoLsb - fetchTransformedBilinear<BlendTransformedBilinear>, // Indexed8 - fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // RGB32 - fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB32 - fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // ARGB32_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB16 - fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8565_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB666 - fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB6666_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB555 - fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8555_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB888 - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB444 - fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB4444_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGBX8888 - fetchTransformedBilinear<BlendTransformedBilinear>, // RGBA8888 - fetchTransformedBilinear<BlendTransformedBilinear>, // RGBA8888_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // BGR30 - fetchTransformedBilinear<BlendTransformedBilinear>, // A2BGR30_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // RGB30 - fetchTransformedBilinear<BlendTransformedBilinear>, // A2RGB30_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinear>, // Alpha8 - fetchTransformedBilinear<BlendTransformedBilinear>, // Grayscale8 - }, - { - 0, // BilinearTiled - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Mono - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // MonoLsb - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Indexed8 - fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // RGB32 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB32 - fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB16 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB666 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB555 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB888 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB444 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB4444_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGBX8888 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGBA8888 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGBA8888_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // BGR30 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // A2BGR30_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB30 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // A2RGB30_Premultiplied - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Alpha8 - fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Grayscale8 - }, +// FetchUntransformed can have more specialized methods added depending on SIMD features. +static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { + 0, // Invalid + fetchUntransformed, // Mono + fetchUntransformed, // MonoLsb + fetchUntransformed, // Indexed8 + fetchUntransformedARGB32PM, // RGB32 + fetchUntransformed, // ARGB32 + fetchUntransformedARGB32PM, // ARGB32_Premultiplied + fetchUntransformedRGB16, // RGB16 + fetchUntransformed, // ARGB8565_Premultiplied + fetchUntransformed, // RGB666 + fetchUntransformed, // ARGB6666_Premultiplied + fetchUntransformed, // RGB555 + fetchUntransformed, // ARGB8555_Premultiplied + fetchUntransformed, // RGB888 + fetchUntransformed, // RGB444 + fetchUntransformed, // ARGB4444_Premultiplied + fetchUntransformed, // RGBX8888 + fetchUntransformed, // RGBA8888 + fetchUntransformed, // RGBA8888_Premultiplied + fetchUntransformed, // Format_BGR30 + fetchUntransformed, // Format_A2BGR30_Premultiplied + fetchUntransformed, // Format_RGB30 + fetchUntransformed, // Format_A2RGB30_Premultiplied + fetchUntransformed, // Alpha8 + fetchUntransformed, // Grayscale8 }; -static SourceFetchProc64 sourceFetch64[NBlendTypes][QImage::NImageFormats] = { - // Untransformed - { - 0, // Invalid - fetchUntransformed64, // Mono - fetchUntransformed64, // MonoLsb - fetchUntransformed64, // Indexed8 - fetchUntransformed64, // RGB32 - fetchUntransformed64, // ARGB32 - fetchUntransformed64, // ARGB32_Premultiplied - fetchUntransformed64, // RGB16 - fetchUntransformed64, // ARGB8565_Premultiplied - fetchUntransformed64, // RGB666 - fetchUntransformed64, // ARGB6666_Premultiplied - fetchUntransformed64, // RGB555 - fetchUntransformed64, // ARGB8555_Premultiplied - fetchUntransformed64, // RGB888 - fetchUntransformed64, // RGB444 - fetchUntransformed64, // ARGB4444_Premultiplied - fetchUntransformed64, // RGBX8888 - fetchUntransformed64, // RGBA8888 - fetchUntransformed64, // RGBA8888_Premultiplied - fetchUntransformed64, // Format_BGR30 - fetchUntransformed64, // Format_A2BGR30_Premultiplied - fetchUntransformed64, // Format_RGB30 - fetchUntransformed64, // Format_A2RGB30_Premultiplied - fetchUntransformed64, // Alpha8 - fetchUntransformed64, // Grayscale8 - }, - // Tiled - { - 0, // Invalid - fetchUntransformed64, // Mono - fetchUntransformed64, // MonoLsb - fetchUntransformed64, // Indexed8 - fetchUntransformed64, // RGB32 - fetchUntransformed64, // ARGB32 - fetchUntransformed64, // ARGB32_Premultiplied - fetchUntransformed64, // RGB16 - fetchUntransformed64, // ARGB8565_Premultiplied - fetchUntransformed64, // RGB666 - fetchUntransformed64, // ARGB6666_Premultiplied - fetchUntransformed64, // RGB555 - fetchUntransformed64, // ARGB8555_Premultiplied - fetchUntransformed64, // RGB888 - fetchUntransformed64, // RGB444 - fetchUntransformed64, // ARGB4444_Premultiplied - fetchUntransformed64, // RGBX8888 - fetchUntransformed64, // RGBA8888 - fetchUntransformed64, // RGBA8888_Premultiplied - fetchUntransformed64, // BGR30 - fetchUntransformed64, // A2BGR30_Premultiplied - fetchUntransformed64, // RGB30 - fetchUntransformed64, // A2RGB30_Premultiplied - fetchUntransformed64, // Alpha8 - fetchUntransformed64, // Grayscale8 - }, - // Transformed - { - 0, // Invalid - fetchTransformed64<BlendTransformed>, // Mono - fetchTransformed64<BlendTransformed>, // MonoLsb - fetchTransformed64<BlendTransformed>, // Indexed8 - fetchTransformed64<BlendTransformed>, // RGB32 - fetchTransformed64<BlendTransformed>, // ARGB32 - fetchTransformed64<BlendTransformed>, // ARGB32_Premultiplied - fetchTransformed64<BlendTransformed>, // RGB16 - fetchTransformed64<BlendTransformed>, // ARGB8565_Premultiplied - fetchTransformed64<BlendTransformed>, // RGB666 - fetchTransformed64<BlendTransformed>, // ARGB6666_Premultiplied - fetchTransformed64<BlendTransformed>, // RGB555 - fetchTransformed64<BlendTransformed>, // ARGB8555_Premultiplied - fetchTransformed64<BlendTransformed>, // RGB888 - fetchTransformed64<BlendTransformed>, // RGB444 - fetchTransformed64<BlendTransformed>, // ARGB4444_Premultiplied - fetchTransformed64<BlendTransformed>, // RGBX8888 - fetchTransformed64<BlendTransformed>, // RGBA8888 - fetchTransformed64<BlendTransformed>, // RGBA8888_Premultiplied - fetchTransformed64<BlendTransformed>, // BGR30 - fetchTransformed64<BlendTransformed>, // A2BGR30_Premultiplied - fetchTransformed64<BlendTransformed>, // RGB30 - fetchTransformed64<BlendTransformed>, // A2RGB30_Premultiplied - fetchTransformed64<BlendTransformed>, // Alpah8 - fetchTransformed64<BlendTransformed>, // Grayscale8 - }, - { - 0, // TransformedTiled - fetchTransformed64<BlendTransformedTiled>, // Mono - fetchTransformed64<BlendTransformedTiled>, // MonoLsb - fetchTransformed64<BlendTransformedTiled>, // Indexed8 - fetchTransformed64<BlendTransformedTiled>, // RGB32 - fetchTransformed64<BlendTransformedTiled>, // ARGB32 - fetchTransformed64<BlendTransformedTiled>, // ARGB32_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGB16 - fetchTransformed64<BlendTransformedTiled>, // ARGB8565_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGB666 - fetchTransformed64<BlendTransformedTiled>, // ARGB6666_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGB555 - fetchTransformed64<BlendTransformedTiled>, // ARGB8555_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGB888 - fetchTransformed64<BlendTransformedTiled>, // RGB444 - fetchTransformed64<BlendTransformedTiled>, // ARGB4444_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGBX8888 - fetchTransformed64<BlendTransformedTiled>, // RGBA8888 - fetchTransformed64<BlendTransformedTiled>, // RGBA8888_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // BGR30 - fetchTransformed64<BlendTransformedTiled>, // A2BGR30_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // RGB30 - fetchTransformed64<BlendTransformedTiled>, // A2RGB30_Premultiplied - fetchTransformed64<BlendTransformedTiled>, // Alpha8 - fetchTransformed64<BlendTransformedTiled>, // Grayscale8 - }, - { - 0, // Bilinear - fetchTransformedBilinear64<BlendTransformedBilinear>, // Mono - fetchTransformedBilinear64<BlendTransformedBilinear>, // MonoLsb - fetchTransformedBilinear64<BlendTransformedBilinear>, // Indexed8 - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB32 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB16 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8565_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB666 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB6666_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB555 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8555_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB888 - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB444 - fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB4444_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBX8888 - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888 - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // BGR30 - fetchTransformedBilinear64<BlendTransformedBilinear>, // A2BGR30_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB30 - fetchTransformedBilinear64<BlendTransformedBilinear>, // A2RGB30_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinear>, // Alpha8 - fetchTransformedBilinear64<BlendTransformedBilinear>, // Grayscale8 - }, - { - 0, // BilinearTiled - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Mono - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // MonoLsb - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Indexed8 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB32 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB16 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB666 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB555 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB888 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB444 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB4444_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBX8888 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // BGR30 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2BGR30_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB30 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2RGB30_Premultiplied - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Alpha8 - fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Grayscale8 - }, +static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = { + fetchUntransformed, // Untransformed + fetchUntransformed, // Tiled + fetchTransformed<BlendTransformed>, // Transformed + fetchTransformed<BlendTransformedTiled>, // TransformedTiled + fetchTransformedBilinear<BlendTransformedBilinear>, // Bilinear + fetchTransformedBilinear<BlendTransformedBilinearTiled> // BilinearTiled +}; + +static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = { + fetchUntransformedARGB32PM, // Untransformed + fetchUntransformedARGB32PM, // Tiled + fetchTransformedARGB32PM<BlendTransformed>, // Transformed + fetchTransformedARGB32PM<BlendTransformedTiled>, // TransformedTiled + fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // Bilinear + fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled +}; + +static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = { + fetchUntransformed64, // Untransformed + fetchUntransformed64, // Tiled + fetchTransformed64<BlendTransformed>, // Transformed + fetchTransformed64<BlendTransformedTiled>, // TransformedTiled + fetchTransformedBilinear64<BlendTransformedBilinear>, // Bilinear + fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled }; +static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) +{ + if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) + return sourceFetchARGB32PM[blendType]; + if (blendType == BlendUntransformed || blendType == BlendTiled) + return sourceFetchUntransformed[format]; + return sourceFetchGeneric[blendType]; +} + + #define FIXPT_BITS 8 #define FIXPT_SIZE (1<<FIXPT_BITS) @@ -3939,8 +3669,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in break; case QSpanData::Texture: solidSource = !data->texture.hasAlpha; - op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format]; - op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format]; + op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format); + op.srcFetch64 = sourceFetchGeneric64[getBlendType(data)]; break; default: Q_UNREACHABLE(); @@ -5483,181 +5213,67 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * /* Image formats here are target formats */ -static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = { - // Untransformed - { - 0, // Invalid - blend_untransformed_generic, // Mono - blend_untransformed_generic, // MonoLsb - blend_untransformed_generic, // Indexed8 - blend_untransformed_generic, // RGB32 - blend_untransformed_generic, // ARGB32 - blend_untransformed_argb, // ARGB32_Premultiplied - blend_untransformed_rgb565, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic_rgb64, - blend_untransformed_generic_rgb64, - blend_untransformed_generic_rgb64, - blend_untransformed_generic_rgb64, - blend_untransformed_generic, - blend_untransformed_generic, - }, - // Tiled - { - 0, // Invalid - blend_tiled_generic, // Mono - blend_tiled_generic, // MonoLsb - blend_tiled_generic, // Indexed8 - blend_tiled_generic, // RGB32 - blend_tiled_generic, // ARGB32 - blend_tiled_argb, // ARGB32_Premultiplied - blend_tiled_rgb565, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic_rgb64, - blend_tiled_generic_rgb64, - blend_tiled_generic_rgb64, - blend_tiled_generic_rgb64, - blend_tiled_generic, - blend_tiled_generic, - }, - // Transformed - { - 0, // Invalid - blend_src_generic, // Mono - blend_src_generic, // MonoLsb - blend_src_generic, // Indexed8 - blend_src_generic, // RGB32 - blend_src_generic, // ARGB32 - blend_transformed_argb, // ARGB32_Premultiplied - blend_transformed_rgb565, - blend_src_generic, // ARGB8565_Premultiplied - blend_src_generic, // RGB666 - blend_src_generic, // ARGB6666_Premultiplied - blend_src_generic, // RGB555 - blend_src_generic, // ARGB8555_Premultiplied - blend_src_generic, // RGB888 - blend_src_generic, // RGB444 - blend_src_generic, // ARGB4444_Premultiplied - blend_src_generic, // RGBX8888 - blend_src_generic, // RGBA8888 - blend_src_generic, // RGBA8888_Premultiplied - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic, - blend_src_generic, - }, - // TransformedTiled - { - 0, - blend_src_generic, // Mono - blend_src_generic, // MonoLsb - blend_src_generic, // Indexed8 - blend_src_generic, // RGB32 - blend_src_generic, // ARGB32 - blend_transformed_tiled_argb, // ARGB32_Premultiplied - blend_transformed_tiled_rgb565, - blend_src_generic, // ARGB8565_Premultiplied - blend_src_generic, // RGB666 - blend_src_generic, // ARGB6666_Premultiplied - blend_src_generic, // RGB555 - blend_src_generic, // ARGB8555_Premultiplied - blend_src_generic, // RGB888 - blend_src_generic, // RGB444 - blend_src_generic, // ARGB4444_Premultiplied - blend_src_generic, // RGBX8888 - blend_src_generic, // RGBA8888 - blend_src_generic, // RGBA8888_Premultiplied - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic, - blend_src_generic, - }, - // Bilinear - { - 0, - blend_src_generic, // Mono - blend_src_generic, // MonoLsb - blend_src_generic, // Indexed8 - blend_src_generic, // RGB32 - blend_src_generic, // ARGB32 - blend_src_generic, // ARGB32_Premultiplied - blend_transformed_bilinear_rgb565, - blend_src_generic, // ARGB8565_Premultiplied - blend_src_generic, // RGB666 - blend_src_generic, // ARGB6666_Premultiplied - blend_src_generic, // RGB555 - blend_src_generic, // ARGB8555_Premultiplied - blend_src_generic, // RGB888 - blend_src_generic, // RGB444 - blend_src_generic, // ARGB4444_Premultiplied - blend_src_generic, // RGBX8888 - blend_src_generic, // RGBA8888 - blend_src_generic, // RGBA8888_Premultiplied - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic_rgb64, - blend_src_generic, - blend_src_generic, - }, - // BilinearTiled - { - 0, - blend_src_generic, // Mono - blend_src_generic, // MonoLsb - blend_src_generic, // Indexed8 - blend_src_generic, // RGB32 - blend_src_generic, // ARGB32 - blend_src_generic, // ARGB32_Premultiplied - blend_src_generic, // RGB16 - blend_src_generic, // ARGB8565_Premultiplied - blend_src_generic, // RGB666 - blend_src_generic, // ARGB6666_Premultiplied - blend_src_generic, // RGB555 - blend_src_generic, // ARGB8555_Premultiplied - blend_src_generic, // RGB888 - blend_src_generic, // RGB444 - blend_src_generic, // ARGB4444_Premultiplied - blend_src_generic, // RGBX8888 - blend_src_generic, // RGBA8888 - blend_src_generic, // RGBA8888_Premultiplied - blend_src_generic_rgb64, // BGR30 - blend_src_generic_rgb64, // A2BGR30_Premultiplied - blend_src_generic_rgb64, // RGB30 - blend_src_generic_rgb64, // A2RGB30_Premultiplied - blend_src_generic, // Alpha8 - blend_src_generic, // Grayscale8 - } +static const ProcessSpans processTextureSpansARGB32PM[NBlendTypes] = { + blend_untransformed_argb, // Untransformed + blend_tiled_argb, // Tiled + blend_transformed_argb, // Transformed + blend_transformed_tiled_argb, // TransformedTiled + blend_src_generic, // TransformedBilinear + blend_src_generic // TransformedBilinearTiled +}; + +static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = { + blend_untransformed_rgb565, // Untransformed + blend_tiled_rgb565, // Tiled + blend_transformed_rgb565, // Transformed + blend_transformed_tiled_rgb565, // TransformedTiled + blend_transformed_bilinear_rgb565, // TransformedBilinear + blend_src_generic // TransformedBilinearTiled +}; + +static const ProcessSpans processTextureSpansGeneric[NBlendTypes] = { + blend_untransformed_generic, // Untransformed + blend_tiled_generic, // Tiled + blend_src_generic, // Transformed + blend_src_generic, // TransformedTiled + blend_src_generic, // TransformedBilinear + blend_src_generic // TransformedBilinearTiled +}; + +static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = { + blend_untransformed_generic_rgb64, // Untransformed + blend_tiled_generic_rgb64, // Tiled + blend_src_generic_rgb64, // Transformed + blend_src_generic_rgb64, // TransformedTiled + blend_src_generic_rgb64, // TransformedBilinear + blend_src_generic_rgb64 // TransformedBilinearTiled }; void qBlendTexture(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format]; + TextureBlendType blendType = getBlendType(data); + ProcessSpans proc; + switch (data->rasterBuffer->format) { + case QImage::Format_ARGB32_Premultiplied: + proc = processTextureSpansARGB32PM[blendType]; + break; + case QImage::Format_RGB16: + proc = processTextureSpansRGB16[blendType]; + break; + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: + proc = processTextureSpansGeneric64[blendType]; + break; + case QImage::Format_Invalid: + Q_UNREACHABLE(); + return; + default: + proc = processTextureSpansGeneric[blendType]; + break; + } proc(count, spans, userData); } @@ -6548,6 +6164,15 @@ static void qInitDrawhelperFunctions() qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; + extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); + extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; + #ifdef QT_COMPILER_SUPPORTS_SSSE3 if (qCpuHasFeature(SSSE3)) { extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl, @@ -6563,8 +6188,7 @@ static void qInitDrawhelperFunctions() qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qStorePixels[QPixelLayout::BPP24] = storePixelsBPP24_ssse3; - sourceFetch[BlendUntransformed][QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3; - sourceFetch[BlendTiled][QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3; + sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3; } #endif // SSSE3 @@ -6592,24 +6216,39 @@ static void qInitDrawhelperFunctions() } #endif -#if defined(QT_COMPILER_SUPPORTS_AVX2) && !defined(__AVX2__) +#if defined(QT_COMPILER_SUPPORTS_AVX2) if (qCpuHasFeature(AVX2)) { +#if !defined(__AVX2__) extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *); qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; +#endif + extern void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, int const_alpha); + extern void qt_blend_argb32_on_argb32_avx2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, int const_alpha); + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2; + + extern void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha); + extern void QT_FASTCALL comp_func_Source_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2; } #endif - extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); - extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; - qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; - qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; - qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; #endif // SSE2 @@ -6634,8 +6273,7 @@ static void qInitDrawhelperFunctions() qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; - sourceFetch[BlendUntransformed][QImage::Format_RGB888] = qt_fetchUntransformed_888_neon; - sourceFetch[BlendTiled][QImage::Format_RGB888] = qt_fetchUntransformed_888_neon; + sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_neon; #if defined(ENABLE_PIXMAN_DRAWHELPERS) // The RGB16 helpers are using Arm32 assemblythat has not been ported to AArch64 @@ -6696,14 +6334,9 @@ static void qInitDrawhelperFunctions() destStoreProc[QImage::Format_ARGB32] = qt_destStoreARGB32_mips_dsp; - sourceFetch[BlendUntransformed][QImage::Format_RGB888] = qt_fetchUntransformed_888_mips_dsp; - sourceFetch[BlendTiled][QImage::Format_RGB888] = qt_fetchUntransformed_888_mips_dsp; - - sourceFetch[BlendUntransformed][QImage::Format_RGB444] = qt_fetchUntransformed_444_mips_dsp; - sourceFetch[BlendTiled][QImage::Format_RGB444] = qt_fetchUntransformed_444_mips_dsp; - - sourceFetch[BlendUntransformed][QImage::Format_ARGB8565_Premultiplied] = qt_fetchUntransformed_argb8565_premultiplied_mips_dsp; - sourceFetch[BlendTiled][QImage::Format_ARGB8565_Premultiplied] = qt_fetchUntransformed_argb8565_premultiplied_mips_dsp; + sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_mips_dsp; + sourceFetchUntransformed[QImage::Format_RGB444] = qt_fetchUntransformed_444_mips_dsp; + sourceFetchUntransformed[QImage::Format_ARGB8565_Premultiplied] = qt_fetchUntransformed_argb8565_premultiplied_mips_dsp; #if defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2) qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_mips_dspr2; diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 35a975c972..01ffd54918 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -37,12 +37,14 @@ ** ****************************************************************************/ -#include <private/qdrawhelper_p.h> +#include "qdrawhelper_p.h" +#include "qdrawingprimitive_sse2_p.h" #if defined(QT_COMPILER_SUPPORTS_AVX2) QT_BEGIN_NAMESPACE +// Autovectorized premultiply functions: const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { @@ -55,6 +57,307 @@ const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint return qt_convertRGBA8888ToARGB32PM(buffer, src, count); } +// Vectorized blend functions: + +// See BYTE_MUL_SSE2 for details. +inline static void BYTE_MUL_AVX2(__m256i &pixelVector, const __m256i &alphaChannel, const __m256i &colorMask, const __m256i &half) +{ + __m256i pixelVectorAG = _mm256_srli_epi16(pixelVector, 8); + __m256i pixelVectorRB = _mm256_and_si256(pixelVector, colorMask); + + pixelVectorAG = _mm256_mullo_epi16(pixelVectorAG, alphaChannel); + pixelVectorRB = _mm256_mullo_epi16(pixelVectorRB, alphaChannel); + + pixelVectorRB = _mm256_add_epi16(pixelVectorRB, _mm256_srli_epi16(pixelVectorRB, 8)); + pixelVectorAG = _mm256_add_epi16(pixelVectorAG, _mm256_srli_epi16(pixelVectorAG, 8)); + pixelVectorRB = _mm256_add_epi16(pixelVectorRB, half); + pixelVectorAG = _mm256_add_epi16(pixelVectorAG, half); + + pixelVectorRB = _mm256_srli_epi16(pixelVectorRB, 8); + pixelVectorAG = _mm256_andnot_si256(colorMask, pixelVectorAG); + + pixelVector = _mm256_or_si256(pixelVectorAG, pixelVectorRB); +} + +// See INTERPOLATE_PIXEL_255_SSE2 for details. +inline static void INTERPOLATE_PIXEL_255_AVX2(const __m256i &srcVector, __m256i &dstVector, const __m256i &alphaChannel, const __m256i &oneMinusAlphaChannel, const __m256i &colorMask, const __m256i &half) +{ + const __m256i srcVectorAG = _mm256_srli_epi16(srcVector, 8); + const __m256i dstVectorAG = _mm256_srli_epi16(dstVector, 8); + const __m256i srcVectorRB = _mm256_and_si256(srcVector, colorMask); + const __m256i dstVectorRB = _mm256_and_si256(dstVector, colorMask); + const __m256i srcVectorAGalpha = _mm256_mullo_epi16(srcVectorAG, alphaChannel); + const __m256i srcVectorRBalpha = _mm256_mullo_epi16(srcVectorRB, alphaChannel); + const __m256i dstVectorAGoneMinusAlpha = _mm256_mullo_epi16(dstVectorAG, oneMinusAlphaChannel); + const __m256i dstVectorRBoneMinusAlpha = _mm256_mullo_epi16(dstVectorRB, oneMinusAlphaChannel); + __m256i finalAG = _mm256_add_epi16(srcVectorAGalpha, dstVectorAGoneMinusAlpha); + __m256i finalRB = _mm256_add_epi16(srcVectorRBalpha, dstVectorRBoneMinusAlpha); + finalAG = _mm256_add_epi16(finalAG, _mm256_srli_epi16(finalAG, 8)); + finalRB = _mm256_add_epi16(finalRB, _mm256_srli_epi16(finalRB, 8)); + finalAG = _mm256_add_epi16(finalAG, half); + finalRB = _mm256_add_epi16(finalRB, half); + finalAG = _mm256_andnot_si256(colorMask, finalAG); + finalRB = _mm256_srli_epi16(finalRB, 8); + + dstVector = _mm256_or_si256(finalAG, finalRB); +} + +// See BLEND_SOURCE_OVER_ARGB32_SSE2 for details. +inline static void BLEND_SOURCE_OVER_ARGB32_AVX2(quint32 *dst, const quint32 *src, const int length) +{ + const __m256i half = _mm256_set1_epi16(0x80); + const __m256i one = _mm256_set1_epi16(0xff); + const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff); + const __m256i alphaMask = _mm256_set1_epi32(0xff000000); + const __m256i offsetMask = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); + const __m256i alphaShuffleMask = _mm256_set_epi8(char(0xff),15,char(0xff),15,char(0xff),11,char(0xff),11,char(0xff),7,char(0xff),7,char(0xff),3,char(0xff),3, + char(0xff),15,char(0xff),15,char(0xff),11,char(0xff),11,char(0xff),7,char(0xff),7,char(0xff),3,char(0xff),3); + + const int minusOffsetToAlignDstOn32Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x7; + + int x = 0; + // Prologue to handle all pixels until dst is 32-byte aligned in one step. + if (minusOffsetToAlignDstOn32Bytes != 0 && x < (length - 7)) { + const __m256i prologueMask = _mm256_sub_epi32(_mm256_set1_epi32(minusOffsetToAlignDstOn32Bytes - 1), offsetMask); + const __m256i srcVector = _mm256_maskload_epi32((const int *)&src[x - minusOffsetToAlignDstOn32Bytes], prologueMask); + const __m256i prologueAlphaMask = _mm256_blendv_epi8(_mm256_setzero_si256(), alphaMask, prologueMask); + if (!_mm256_testz_si256(srcVector, prologueAlphaMask)) { + if (_mm256_testc_si256(srcVector, prologueAlphaMask)) { + _mm256_maskstore_epi32((int *)&dst[x - minusOffsetToAlignDstOn32Bytes], prologueMask, srcVector); + } else { + __m256i alphaChannel = _mm256_shuffle_epi8(srcVector, alphaShuffleMask); + alphaChannel = _mm256_sub_epi16(one, alphaChannel); + __m256i dstVector = _mm256_maskload_epi32((int *)&dst[x - minusOffsetToAlignDstOn32Bytes], prologueMask); + BYTE_MUL_AVX2(dstVector, alphaChannel, colorMask, half); + dstVector = _mm256_add_epi8(dstVector, srcVector); + _mm256_maskstore_epi32((int *)&dst[x - minusOffsetToAlignDstOn32Bytes], prologueMask, dstVector); + } + } + x += (8 - minusOffsetToAlignDstOn32Bytes); + } + + for (; x < (length - 7); x += 8) { + const __m256i srcVector = _mm256_lddqu_si256((const __m256i *)&src[x]); + if (!_mm256_testz_si256(srcVector, alphaMask)) { + if (_mm256_testc_si256(srcVector, alphaMask)) { + _mm256_store_si256((__m256i *)&dst[x], srcVector); + } else { + __m256i alphaChannel = _mm256_shuffle_epi8(srcVector, alphaShuffleMask); + alphaChannel = _mm256_sub_epi16(one, alphaChannel); + __m256i dstVector = _mm256_load_si256((__m256i *)&dst[x]); + BYTE_MUL_AVX2(dstVector, alphaChannel, colorMask, half); + dstVector = _mm256_add_epi8(dstVector, srcVector); + _mm256_store_si256((__m256i *)&dst[x], dstVector); + } + } + } + + // Epilogue to handle all remaining pixels in one step. + if (x < length) { + const __m256i epilogueMask = _mm256_add_epi32(offsetMask, _mm256_set1_epi32(x - length)); + const __m256i srcVector = _mm256_maskload_epi32((const int *)&src[x], epilogueMask); + const __m256i epilogueAlphaMask = _mm256_blendv_epi8(_mm256_setzero_si256(), alphaMask, epilogueMask); + if (!_mm256_testz_si256(srcVector, epilogueAlphaMask)) { + if (_mm256_testc_si256(srcVector, epilogueAlphaMask)) { + _mm256_maskstore_epi32((int *)&dst[x], epilogueMask, srcVector); + } else { + __m256i alphaChannel = _mm256_shuffle_epi8(srcVector, alphaShuffleMask); + alphaChannel = _mm256_sub_epi16(one, alphaChannel); + __m256i dstVector = _mm256_maskload_epi32((int *)&dst[x], epilogueMask); + BYTE_MUL_AVX2(dstVector, alphaChannel, colorMask, half); + dstVector = _mm256_add_epi8(dstVector, srcVector); + _mm256_maskstore_epi32((int *)&dst[x], epilogueMask, dstVector); + } + } + } +} + + +// See BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2 for details. +inline static void BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_AVX2(quint32 *dst, const quint32 *src, const int length, const int const_alpha) +{ + int x = 0; + + ALIGNMENT_PROLOGUE_32BYTES(dst, x, length) + blend_pixel(dst[x], src[x], const_alpha); + + const __m256i half = _mm256_set1_epi16(0x80); + const __m256i one = _mm256_set1_epi16(0xff); + const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff); + const __m256i alphaMask = _mm256_set1_epi32(0xff000000); + const __m256i alphaShuffleMask = _mm256_set_epi8(char(0xff),15,char(0xff),15,char(0xff),11,char(0xff),11,char(0xff),7,char(0xff),7,char(0xff),3,char(0xff),3, + char(0xff),15,char(0xff),15,char(0xff),11,char(0xff),11,char(0xff),7,char(0xff),7,char(0xff),3,char(0xff),3); + const __m256i constAlphaVector = _mm256_set1_epi16(const_alpha); + for (; x < (length - 7); x += 8) { + __m256i srcVector = _mm256_lddqu_si256((const __m256i *)&src[x]); + if (!_mm256_testz_si256(srcVector, alphaMask)) { + BYTE_MUL_AVX2(srcVector, constAlphaVector, colorMask, half); + + __m256i alphaChannel = _mm256_shuffle_epi8(srcVector, alphaShuffleMask); + alphaChannel = _mm256_sub_epi16(one, alphaChannel); + __m256i dstVector = _mm256_load_si256((__m256i *)&dst[x]); + BYTE_MUL_AVX2(dstVector, alphaChannel, colorMask, half); + dstVector = _mm256_add_epi8(dstVector, srcVector); + _mm256_store_si256((__m256i *)&dst[x], dstVector); + } + } + for (; x < length; ++x) + blend_pixel(dst[x], src[x], const_alpha); +} + +void qt_blend_argb32_on_argb32_avx2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + if (const_alpha == 256) { + for (int y = 0; y < h; ++y) { + const quint32 *src = reinterpret_cast<const quint32 *>(srcPixels); + quint32 *dst = reinterpret_cast<quint32 *>(destPixels); + BLEND_SOURCE_OVER_ARGB32_AVX2(dst, src, w); + destPixels += dbpl; + srcPixels += sbpl; + } + } else if (const_alpha != 0) { + const_alpha = (const_alpha * 255) >> 8; + for (int y = 0; y < h; ++y) { + const quint32 *src = reinterpret_cast<const quint32 *>(srcPixels); + quint32 *dst = reinterpret_cast<quint32 *>(destPixels); + BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_AVX2(dst, src, w, const_alpha); + destPixels += dbpl; + srcPixels += sbpl; + } + } +} + +void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + if (const_alpha == 256) { + for (int y = 0; y < h; ++y) { + const quint32 *src = reinterpret_cast<const quint32 *>(srcPixels); + quint32 *dst = reinterpret_cast<quint32 *>(destPixels); + ::memcpy(dst, src, w * sizeof(uint)); + srcPixels += sbpl; + destPixels += dbpl; + } + return; + } + if (const_alpha == 0) + return; + + const __m256i half = _mm256_set1_epi16(0x80); + const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff); + + const_alpha = (const_alpha * 255) >> 8; + int one_minus_const_alpha = 255 - const_alpha; + const __m256i constAlphaVector = _mm256_set1_epi16(const_alpha); + const __m256i oneMinusConstAlpha = _mm256_set1_epi16(one_minus_const_alpha); + for (int y = 0; y < h; ++y) { + const quint32 *src = reinterpret_cast<const quint32 *>(srcPixels); + quint32 *dst = reinterpret_cast<quint32 *>(destPixels); + int x = 0; + + // First, align dest to 32 bytes: + ALIGNMENT_PROLOGUE_32BYTES(dst, x, w) + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); + + // 2) interpolate pixels with AVX2 + for (; x < (w - 7); x += 8) { + const __m256i srcVector = _mm256_lddqu_si256((const __m256i *)&src[x]); + if (!_mm256_testc_si256(srcVector, _mm256_setzero_si256())) { + __m256i dstVector = _mm256_load_si256((__m256i *)&dst[x]); + INTERPOLATE_PIXEL_255_AVX2(srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half); + _mm256_store_si256((__m256i *)&dst[x], dstVector); + } + } + + // 3) Epilogue + for (; x < w; ++x) + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); + + srcPixels += sbpl; + destPixels += dbpl; + } +} + +void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha) +{ + Q_ASSERT(const_alpha < 256); + + const quint32 *src = (const quint32 *) srcPixels; + quint32 *dst = (quint32 *) destPixels; + + if (const_alpha == 255) + BLEND_SOURCE_OVER_ARGB32_AVX2(dst, src, length); + else + BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_AVX2(dst, src, length, const_alpha); +} + +void QT_FASTCALL comp_func_Source_avx2(uint *dst, const uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + ::memcpy(dst, src, length * sizeof(uint)); + } else { + const int ialpha = 255 - const_alpha; + + int x = 0; + + // 1) prologue, align on 32 bytes + ALIGNMENT_PROLOGUE_32BYTES(dst, x, length) + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], ialpha); + + // 2) interpolate pixels with AVX2 + const __m256i half = _mm256_set1_epi16(0x80); + const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff); + const __m256i constAlphaVector = _mm256_set1_epi16(const_alpha); + const __m256i oneMinusConstAlpha = _mm256_set1_epi16(ialpha); + for (; x < length - 7; x += 8) { + const __m256i srcVector = _mm256_lddqu_si256((const __m256i *)&src[x]); + __m256i dstVector = _mm256_load_si256((__m256i *)&dst[x]); + INTERPOLATE_PIXEL_255_AVX2(srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half); + _mm256_store_si256((__m256i *)&dst[x], dstVector); + } + + // 3) Epilogue + for (; x < length; ++x) + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], ialpha); + } +} + +void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha) +{ + if ((const_alpha & qAlpha(color)) == 255) { + qt_memfill32(destPixels, color, length); + } else { + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + + const quint32 minusAlphaOfColor = qAlpha(~color); + int x = 0; + + quint32 *dst = (quint32 *) destPixels; + const __m256i colorVector = _mm256_set1_epi32(color); + const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff); + const __m256i half = _mm256_set1_epi16(0x80); + const __m256i minusAlphaOfColorVector = _mm256_set1_epi16(minusAlphaOfColor); + + ALIGNMENT_PROLOGUE_32BYTES(dst, x, length) + destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor); + + for (; x < length - 7; x += 8) { + __m256i dstVector = _mm256_load_si256((__m256i *)&dst[x]); + BYTE_MUL_AVX2(dstVector, minusAlphaOfColorVector, colorMask, half); + dstVector = _mm256_add_epi8(colorVector, dstVector); + _mm256_store_si256((__m256i *)&dst[x], dstVector); + } + for (; x < length; ++x) + destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor); + } +} + QT_END_NAMESPACE #endif diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h index 1a1df547bb..9d511f9bad 100644 --- a/src/gui/painting/qpaintengine_p.h +++ b/src/gui/painting/qpaintengine_p.h @@ -118,6 +118,11 @@ public: virtual void systemStateChanged() { } void drawBoxTextItem(const QPointF &p, const QTextItemInt &ti); + + static QPaintEnginePrivate *get(QPaintEngine *paintEngine) { return paintEngine->d_func(); } + + virtual QPaintEngine *aggregateEngine() { return 0; } + virtual Qt::HANDLE nativeHandle() { return 0; } }; QT_END_NAMESPACE |