QShaderGraph: don't generate statements with undefined inputs

This fixes the shader generation for graphs like this one:

                 Function0 ------> Output0
            (with unbound input)

   Input ------> Function1 ------> Output1

With those graphs, createStatements will not return any statement for
nodes Function0 and Output0.

Change-Id: Iec32aa51623e176b03ae23e580f06d14df80a194
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
(cherry picked from commit 7981dbfaf371a368fbd69e935768b310f42a0e5a)
This commit is contained in:
Nicolas Guichard 2020-02-19 12:38:27 +01:00 committed by Paul Lemire
parent b150901525
commit 34369b5e90
2 changed files with 51 additions and 8 deletions

View File

@ -123,6 +123,50 @@ namespace
}
return targetStatement;
}
void removeNodesWithUnboundInputs(QVector<QShaderGraph::Statement> &statements,
const QVector<QShaderGraph::Edge> &allEdges)
{
// A node is invalid if any of its input ports is disconected
// or connected to the output port of another invalid node.
// Keeps track of the edges from the nodes we know to be valid
// to unvisited nodes
auto currentEdges = QVector<QShaderGraph::Edge>();
statements.erase(std::remove_if(statements.begin(),
statements.end(),
[&currentEdges, &allEdges] (const QShaderGraph::Statement &statement) {
const QShaderNode &node = statement.node;
const QVector<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, node.uuid());
const QVector<QShaderNodePort> ports = node.ports();
bool allInputsConnected = true;
for (const QShaderNodePort &port : node.ports()) {
if (port.direction == QShaderNodePort::Output)
continue;
const auto edgeIt = std::find_if(outgoing.cbegin(),
outgoing.cend(),
[&port] (const QShaderGraph::Edge &edge) {
return edge.targetPortName == port.name;
});
if (edgeIt != outgoing.cend())
currentEdges.removeAll(*edgeIt);
else
allInputsConnected = false;
}
if (allInputsConnected) {
const QVector<QShaderGraph::Edge> incoming = incomingEdges(allEdges, node.uuid());
currentEdges.append(incoming);
}
return !allInputsConnected;
}),
statements.end());
}
}
QUuid QShaderGraph::Statement::uuid() const Q_DECL_NOTHROW
@ -248,6 +292,9 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
}
std::reverse(result.begin(), result.end());
removeNodesWithUnboundInputs(result, enabledEdges);
return result;
}

View File

@ -516,12 +516,9 @@ void tst_QShaderGraph::shouldHandleUnboundPortsDuringGraphSerialization()
const auto statements = graph.createStatements();
// THEN
// Note that no edge leads to the unbound input
// Note that no statement has any unbound input
const auto expected = QVector<QShaderGraph::Statement>()
<< createStatement(input, {}, {0})
<< createStatement(function, {-1, 0, -1}, {2, 3, 4})
<< createStatement(unboundOutput, {-1}, {})
<< createStatement(output, {3}, {});
<< createStatement(input, {}, {0});
dumpStatementsIfNeeded(statements, expected);
QCOMPARE(statements, expected);
}
@ -568,9 +565,8 @@ void tst_QShaderGraph::shouldSurviveCyclesDuringGraphSerialization()
const auto statements = graph.createStatements();
// THEN
// Obviously will lead to a compile failure later on since it cuts everything beyond the cycle
const auto expected = QVector<QShaderGraph::Statement>()
<< createStatement(output, {2}, {});
// The cycle is ignored
const auto expected = QVector<QShaderGraph::Statement>();
dumpStatementsIfNeeded(statements, expected);
QCOMPARE(statements, expected);
}