diff options
author | Liang Qi <liang.qi@qt.io> | 2019-04-24 09:52:30 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-04-24 09:52:30 +0200 |
commit | dc373186841802f2dd17fcd243efdeca7d5433e9 (patch) | |
tree | 4fff0a3366b63db97ca5a8b04a220bb0b8c56450 /src/gui | |
parent | 7d646508c8219408f90103ed13613db8d01a4065 (diff) | |
parent | cb10ec56f733c34d23c9e5511b19c1e508d0f13f (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
src/gui/util/qshaderformat.cpp
src/gui/util/qshaderformat_p.h
src/widgets/graphicsview/qgraphicsitem_p.h
Change-Id: Idafd88eb9a0a15b4af29f6143d009c1ec8ceecca
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qoffscreensurface.cpp | 8 | ||||
-rw-r--r-- | src/gui/painting/qcoregraphics.mm | 158 | ||||
-rw-r--r-- | src/gui/painting/qcoregraphics_p.h | 36 | ||||
-rw-r--r-- | src/gui/util/qshaderformat.cpp | 17 | ||||
-rw-r--r-- | src/gui/util/qshaderformat_p.h | 13 | ||||
-rw-r--r-- | src/gui/util/qshadergenerator.cpp | 67 | ||||
-rw-r--r-- | src/gui/util/qshadernodesloader.cpp | 11 |
7 files changed, 205 insertions, 105 deletions
diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp index ae027af627..0cc11ca3bb 100644 --- a/src/gui/kernel/qoffscreensurface.cpp +++ b/src/gui/kernel/qoffscreensurface.cpp @@ -46,6 +46,8 @@ #include "qwindow.h" #include "qplatformwindow.h" +#include <private/qwindow_p.h> + QT_BEGIN_NAMESPACE /*! @@ -199,12 +201,18 @@ void QOffscreenSurface::create() if (QThread::currentThread() != qGuiApp->thread()) qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."); d->offscreenWindow = new QWindow(d->screen); + // Make the window frameless to prevent Windows from enlarging it, should it + // violate the minimum title bar width on the platform. + d->offscreenWindow->setFlags(d->offscreenWindow->flags() + | Qt::CustomizeWindowHint | Qt::FramelessWindowHint); d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface")); // Remove this window from the global list since we do not want it to be destroyed when closing the app. // The QOffscreenSurface has to be usable even after exiting the event loop. QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow); d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface); d->offscreenWindow->setFormat(d->requestedFormat); + // Prevent QPlatformWindow::initialGeometry() and platforms from setting a default geometry. + qt_window_private(d->offscreenWindow)->setAutomaticPositionAndResizeEnabled(false); d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height()); d->offscreenWindow->create(); } diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index 53066687d3..e2497eaadb 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -366,40 +366,35 @@ void qt_mac_scale_region(QRegion *region, qreal scaleFactor) // ---------------------- QMacCGContext ---------------------- -QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) +QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) { - // 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. - - QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); + initialize(paintDevice); +} - CGContextTranslateCTM(context, 0, image->height()); - const qreal devicePixelRatio = paintDevice->devicePixelRatioF(); - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextScaleCTM(context, 1, -1); +void QMacCGContext::initialize(QPaintDevice *paintDevice) +{ + // Find the underlying QImage of the paint device + switch (int deviceType = paintDevice->devType()) { + case QInternal::Pixmap: { + auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle(); + if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass) + initialize(platformPixmap->buffer()); + else + qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId(); + break; + } + case QInternal::Image: + initialize(static_cast<const QImage *>(paintDevice)); + break; + case QInternal::Widget: + qWarning() << "QMacCGContext: not implemented: Widget class"; + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType; + } } -QMacCGContext::QMacCGContext(QPainter *painter) : context(0) +QMacCGContext::QMacCGContext(QPainter *painter) { QPaintEngine *paintEngine = painter->paintEngine(); @@ -414,51 +409,68 @@ QMacCGContext::QMacCGContext(QPainter *painter) : context(0) return; } - int devType = painter->device()->devType(); - if (paintEngine->type() == QPaintEngine::Raster - && (devType == QInternal::Widget || - devType == QInternal::Pixmap || - devType == QInternal::Image)) { - - const QImage *image = static_cast<const QImage *>(paintEngine->paintDevice()); - QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); - - // 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); + if (paintEngine->type() != QPaintEngine::Raster) { + qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type(); + return; + } + + // The raster paint engine always operates on a QImage + Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image); + + // On behalf of one of these supported painter devices + switch (int painterDeviceType = painter->device()->devType()) { + case QInternal::Pixmap: + case QInternal::Image: + case QInternal::Widget: + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType; + return; + } + + // Applying the clip is so entangled with the rest of the context setup + // that for simplicity we just pass in the painter. + initialize(static_cast<const QImage *>(paintEngine->paintDevice()), painter); +} + +void QMacCGContext::initialize(const QImage *image, QPainter *painter) +{ + QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, + image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); + + // Invert y axis + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); + + const qreal devicePixelRatio = image->devicePixelRatio(); + + if (painter && painter->device()->devType() == QInternal::Widget) { + // Set the clip rect which is an intersection of the system clip and the painter clip + QRegion clip = painter->paintEngine()->systemClip(); + QTransform deviceTransform = painter->deviceTransform(); + + if (painter->hasClipping()) { + // To make matters more interesting the painter clip is in device-independent pixels, + // so we need to scale it to match the device-pixels of the system clip. + QRegion painterClip = painter->clipRegion(); + qt_mac_scale_region(&painterClip, devicePixelRatio); + + painterClip.translate(deviceTransform.dx(), deviceTransform.dy()); + + if (clip.isEmpty()) + clip = painterClip; + else + clip &= painterClip; } - } else { - qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; + + qt_mac_clip_cg(context, clip, 0); + + CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy()); } + + // Scale the context so that painting happens in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); } QT_END_NAMESPACE diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h index 868c2b08b5..ba2cde8325 100644 --- a/src/gui/painting/qcoregraphics_p.h +++ b/src/gui/painting/qcoregraphics_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <QtCore/private/qcore_mac_p.h> + #include <QtGui/private/qtguiglobal_p.h> #include <QtGui/qregion.h> #include <QtGui/qpalette.h> @@ -89,38 +91,16 @@ Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color); class Q_GUI_EXPORT QMacCGContext { public: - inline QMacCGContext() { context = 0; } + QMacCGContext() = default; 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; - } + + operator CGContextRef() { return context; } private: - CGContextRef context; + void initialize(QPaintDevice *paintDevice); + void initialize(const QImage *, QPainter *painter = nullptr); + QCFType<CGContextRef> context; }; QT_END_NAMESPACE diff --git a/src/gui/util/qshaderformat.cpp b/src/gui/util/qshaderformat.cpp index 324d84ffe1..ea86dd6ca5 100644 --- a/src/gui/util/qshaderformat.cpp +++ b/src/gui/util/qshaderformat.cpp @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE QShaderFormat::QShaderFormat() noexcept : m_api(NoApi) + , m_shaderType(Fragment) { } @@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const noexcept if (m_version < other.m_version) return false; + if (m_shaderType != other.m_shaderType) + return false; + const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(), m_extensions.constEnd(), other.m_extensions.constBegin(), @@ -119,12 +123,23 @@ bool QShaderFormat::supports(const QShaderFormat &other) const noexcept return true; } +QShaderFormat::ShaderType QShaderFormat::shaderType() const Q_DECL_NOTHROW +{ + return m_shaderType; +} + +void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) Q_DECL_NOTHROW +{ + m_shaderType = shaderType; +} + bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept { return lhs.api() == rhs.api() && lhs.version() == rhs.version() && lhs.extensions() == rhs.extensions() - && lhs.vendor() == rhs.vendor(); + && lhs.vendor() == rhs.vendor() + && lhs.shaderType() == rhs.shaderType(); } QT_END_NAMESPACE diff --git a/src/gui/util/qshaderformat_p.h b/src/gui/util/qshaderformat_p.h index 84bf71fdb6..c50d7d5729 100644 --- a/src/gui/util/qshaderformat_p.h +++ b/src/gui/util/qshaderformat_p.h @@ -69,6 +69,15 @@ public: OpenGLES }; + enum ShaderType : int { + Vertex = 0, + TessellationControl, + TessellationEvaluation, + Geometry, + Fragment, + Compute + }; + Q_GUI_EXPORT QShaderFormat() noexcept; Q_GUI_EXPORT Api api() const noexcept; @@ -86,11 +95,15 @@ public: Q_GUI_EXPORT bool isValid() const noexcept; Q_GUI_EXPORT bool supports(const QShaderFormat &other) const noexcept; + Q_GUI_EXPORT ShaderType shaderType() const Q_DECL_NOTHROW; + Q_GUI_EXPORT void setShaderType(ShaderType shaderType) Q_DECL_NOTHROW; + private: Api m_api; QVersionNumber m_version; QStringList m_extensions; QString m_vendor; + ShaderType m_shaderType; }; Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept; diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 60cf5a2fc5..205118f41c 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -40,6 +40,7 @@ #include "qshadergenerator_p.h" #include "qshaderlanguage_p.h" +#include <QRegularExpression> QT_BEGIN_NAMESPACE @@ -56,7 +57,10 @@ namespace case QShaderLanguage::Const: return "const"; case QShaderLanguage::Input: - return "varying"; + if (format.shaderType() == QShaderFormat::Vertex) + return "attribute"; + else + return "varying"; case QShaderLanguage::Output: return ""; // Although fragment shaders for <=2 only have fixed outputs case QShaderLanguage::Uniform: @@ -314,12 +318,22 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) [enabledLayers] (const QString &s) { return enabledLayers.contains(s); }); }; + QVector<QString> globalInputVariables; + const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$")); + const QVector<QShaderNode> nodes = graph.nodes(); for (const QShaderNode &node : nodes) { if (intersectsEnabledLayers(node.layers())) { const QByteArrayList headerSnippets = node.rule(format).headerSnippets; for (const QByteArray &snippet : headerSnippets) { code << replaceParameters(snippet, node, format); + + // If node is an input, record the variable name into the globalInputVariables vector + if (node.type() == QShaderNode::Input) { + const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last())); + if (match.hasMatch()) + globalInputVariables.push_back(match.captured(1)); + } } } } @@ -328,6 +342,14 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); + // Table to store temporary variables that should be replaced by global + // variables. This avoids having vec3 v56 = vertexPosition; when we could + // just use vertexPosition directly. + // The added benefit is when having arrays, we don't try to create + // mat4 v38 = skinningPalelette[100] which would be invalid + QHash<QString, QString> localReferencesToGlobalInputs; + const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*(\\w+).*;$")); + for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) { const QShaderNode node = statement.node; QByteArray line = node.rule(format).substitution; @@ -338,6 +360,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const bool isInput = port.direction == QShaderNodePort::Input; const int portIndex = statement.portIndex(portDirection, portName); + + Q_ASSERT(portIndex >= 0); + const int variableIndex = isInput ? statement.inputs.at(portIndex) : statement.outputs.at(portIndex); if (variableIndex < 0) @@ -345,15 +370,51 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); + line.replace(placeholder, variable); } - code << QByteArrayLiteral(" ") + replaceParameters(line, node, format); + const QByteArray substitutionedLine = replaceParameters(line, node, format); + + // Record name of temporary variable that possibly references a global input + // We will replace the temporary variables by the matching global variables later + bool isAGlobalInputVariable = false; + if (node.type() == QShaderNode::Input) { + const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine)); + if (match.hasMatch()) { + const QString globalVariable = match.captured(2); + if (globalInputVariables.contains(globalVariable)) { + const QString localVariable = match.captured(1); + // TO DO: Clean globalVariable (remove brackets ...) + localReferencesToGlobalInputs.insert(localVariable, globalVariable); + isAGlobalInputVariable = true; + } + } + } + + // Only insert content for lines aren't inputs or have not matching + // globalVariables for now + if (!isAGlobalInputVariable) + code << QByteArrayLiteral(" ") + substitutionedLine; } code << QByteArrayLiteral("}"); code << QByteArray(); - return code.join('\n'); + + // Replace occurrences of local variables which reference a global variable + // by the global variables directly + auto it = localReferencesToGlobalInputs.cbegin(); + const auto end = localReferencesToGlobalInputs.cend(); + QString codeString = QString::fromUtf8(code.join('\n')); + + while (it != end) { + const QRegularExpression r(QStringLiteral("\\b(%1)([\\b|\\.|;|\\)|\\[|\\s|\\*|\\+|\\/|\\-|,])").arg(it.key()), + QRegularExpression::MultilineOption); + codeString.replace(r, QStringLiteral("%1\\2").arg(it.value())); + ++it; + } + + return codeString.toUtf8(); } QT_END_NAMESPACE diff --git a/src/gui/util/qshadernodesloader.cpp b/src/gui/util/qshadernodesloader.cpp index af565c906d..922479332c 100644 --- a/src/gui/util/qshadernodesloader.cpp +++ b/src/gui/util/qshadernodesloader.cpp @@ -251,6 +251,17 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) break; } + // We default out to a Fragment ShaderType if nothing is specified + // as that was the initial behavior we introduced + const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString(); + format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment + : shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex + : shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl + : shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation + : shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry + : shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute + : QShaderFormat::Fragment); + const QByteArray substitution = substitutionValue.toString().toUtf8(); const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets")); |