From b150901525958f3d6e2a1cef1f49bda24c94a3fd Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Tue, 18 Feb 2020 17:16:14 +0100 Subject: QShaderGenerator: Don't crash when a node has multiple outputs It was already possible to declare a node prototype with multiple outputs, but trying to assign to all those outputs was not possible and instead resulted in a crash. It is now possible to declare nodes like this without crashing: "SEPERATE_XYZ": { "inputs": ["vector"], "outputs": ["x", "y", "z"], "rules": [ { "substitution": "float $x = $vector.x; float $y = $vector.y; float $z = $vector.z;" } ] } Change-Id: I748e77e84c9120dc688c573eee33dc13c6bfbace Reviewed-by: Paul Lemire (cherry picked from commit 39994e0705f11afc45e20872b95fb3a6e684c913) --- src/gui/util/qshadergenerator.cpp | 67 +++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 7ea42a7c9a..244b95605b 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -346,10 +346,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); - const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+)).*;$")); - const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("^(.*\\s+(v\\d+))\\s*=\\s*(.*);$")); + const QRegularExpression localToGlobalRegExp(QStringLiteral("[^;]*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+))[^;]*;")); + const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);")); const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*")); - const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("^\\s*(\\w+)\\s*=\\s*(.*);$")); + const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);")); struct Variable; @@ -517,14 +517,31 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Substitute variable names by generated vN variable names const QByteArray substitutionedLine = replaceParameters(line, node, format); - Variable *v = nullptr; + QRegularExpressionMatchIterator matches; switch (node.type()) { - // Record name of temporary variable that possibly references a global input - // We will replace the temporary variables by the matching global variables later - case QShaderNode::Input: { - const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Input: + matches = localToGlobalRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Function: + matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Output: + matches = outputToTemporaryAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Invalid: + break; + } + + while (matches.hasNext()) { + QRegularExpressionMatch match = matches.next(); + + Variable *v = nullptr; + + switch (node.type()) { + // Record name of temporary variable that possibly references a global input + // We will replace the temporary variables by the matching global variables later + case QShaderNode::Input: { const QString localVariable = match.captured(1); const QString globalVariable = match.captured(2); @@ -535,13 +552,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) Assignment assignment; assignment.expression = globalVariable; v->assignment = assignment; + break; } - break; - } - case QShaderNode::Function: { - const QRegularExpressionMatch match = temporaryVariableToAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Function: { const QString localVariableDeclaration = match.captured(1); const QString localVariableName = match.captured(2); const QString assignmentContent = match.captured(3); @@ -554,13 +568,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; } - break; - } - case QShaderNode::Output: { - const QRegularExpressionMatch match = outputToTemporaryAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Output: { const QString outputDeclaration = match.captured(1); const QString assignmentContent = match.captured(2); @@ -575,17 +586,17 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; + } + case QShaderNode::Invalid: + break; } - break; - } - case QShaderNode::Invalid: - break; - } - LineContent lineContent; - lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); - lineContent.var = v; - lines << lineContent; + LineContent lineContent; + lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); + lineContent.var = v; + lines << lineContent; + } } // Go through all lines -- cgit v1.2.3