QShaderGenerator: Allow more expressions in input nodes

Currently QShaderGenerator will crash when encountering some expressions
in input nodes.

For example, this node prototype would make it crash:
"VERTEX_COLOR": {
  "outputs": ["color", "alpha"],
  "rules": [
    "headerSnippets": ["in vec4 vertexColor;"],
    "substitution": "vec3 $color = vertexColor.rgb;
                     float $alpha = vertexColor.a;"
  ]
}

Change-Id: I37abb8099d376843a4cb13228140467dc1b8f60c
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
(cherry picked from commit f9086ebd0198c53e8a811af47e0ff0c84d78eb30)
This commit is contained in:
Nicolas Guichard 2020-02-18 17:40:04 +01:00 committed by Paul Lemire
parent 157be588f7
commit 8c8f4c8c48
2 changed files with 53 additions and 6 deletions

View File

@ -346,10 +346,9 @@ 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 temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*"));
const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);"));
const QRegularExpression statementRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);"));
struct Variable;
@ -521,14 +520,12 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
switch (node.type()) {
case QShaderNode::Input:
matches = localToGlobalRegExp.globalMatch(QString::fromUtf8(substitutionedLine));
case QShaderNode::Output:
matches = statementRegExp.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;
}

View File

@ -200,6 +200,7 @@ private slots:
void shouldGenerateTemporariesWisely();
void shouldHandlePortNamesPrefixingOneAnother();
void shouldHandleNodesWithMultipleOutputPorts();
void shouldHandleExpressionsInInputNodes();
};
void tst_QShaderGenerator::shouldHaveDefaultState()
@ -1372,6 +1373,55 @@ void tst_QShaderGenerator::shouldHandleNodesWithMultipleOutputPorts()
QCOMPARE(code, expected.join("\n"));
}
void tst_QShaderGenerator::shouldHandleExpressionsInInputNodes()
{
// GIVEN
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
auto input = createNode({
createPort(QShaderNodePort::Output, "output")
});
input.addRule(gl4, QShaderNode::Rule("float $output = 3 + 4;"));
auto output = createNode({
createPort(QShaderNodePort::Input, "input")
});
output.addRule(gl4, QShaderNode::Rule("globalOut = $input;",
QByteArrayList() << "out float globalOut;"));
// WHEN
const auto graph = [=] {
auto res = QShaderGraph();
res.addNode(input);
res.addNode(output);
res.addEdge(createEdge(input.uuid(), "output", output.uuid(), "input"));
return res;
}();
auto generator = QShaderGenerator();
generator.graph = graph;
generator.format = gl4;
const auto code = generator.createShaderCode();
// THEN
const auto expected = QByteArrayList()
<< "#version 400 core"
<< ""
<< "out float globalOut;"
<< ""
<< "void main()"
<< "{"
<< " globalOut = 3 + 4;"
<< "}"
<< "";
QCOMPARE(code, expected.join("\n"));
}
QTEST_MAIN(tst_QShaderGenerator)
#include "tst_qshadergenerator.moc"