diff options
author | Liang Qi <liang.qi@qt.io> | 2019-04-16 09:34:50 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-04-16 09:34:50 +0200 |
commit | 9d67bf6e9635505bd9523a3007f8e531f890c88f (patch) | |
tree | a4b8a21313b4ac66bb1e96d90504a001863e2f22 /src/gui/util | |
parent | 12b96dbb81a1a7bc5ffc08c24942038b007985e9 (diff) | |
parent | 5b3dfa470ed7ea40103daa785286ab71fb7aa230 (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts:
src/corelib/tools/qlocale.qdoc
tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
Done-with: Edward Welbourne <edward.welbourne@qt.io>
Done-with: Volker Hilsheimer <volker.hilsheimer@qt.io>
Change-Id: I88e0757b2d020f0a244714c87844631df4b3fd13
Diffstat (limited to 'src/gui/util')
-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 |
4 files changed, 104 insertions, 4 deletions
diff --git a/src/gui/util/qshaderformat.cpp b/src/gui/util/qshaderformat.cpp index 373bfb9e7e..e4e3718199 100644 --- a/src/gui/util/qshaderformat.cpp +++ b/src/gui/util/qshaderformat.cpp @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE QShaderFormat::QShaderFormat() Q_DECL_NOTHROW : m_api(NoApi) + , m_shaderType(Fragment) { } @@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW 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 Q_DECL_NOTHROW 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) Q_DECL_NOTHROW { 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 064c2364a7..8d5e83bd22 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() Q_DECL_NOTHROW; Q_GUI_EXPORT Api api() const Q_DECL_NOTHROW; @@ -86,11 +95,15 @@ public: Q_GUI_EXPORT bool isValid() const Q_DECL_NOTHROW; Q_GUI_EXPORT bool supports(const QShaderFormat &other) const Q_DECL_NOTHROW; + 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) Q_DECL_NOTHROW; 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 9badbb94df..5369e8bd4c 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")); |