Implement graph layers support in QShaderGenerator
Change-Id: I823f7866bc5e1f3b262f1aacf4c341dabda7305d Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
This commit is contained in:
parent
236284357f
commit
4bfff6a98b
@ -279,7 +279,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray QShaderGenerator::createShaderCode() const
|
||||
QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
|
||||
{
|
||||
auto code = QByteArrayList();
|
||||
|
||||
@ -303,9 +303,17 @@ QByteArray QShaderGenerator::createShaderCode() const
|
||||
code << QByteArray();
|
||||
}
|
||||
|
||||
const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
|
||||
return layers.isEmpty()
|
||||
|| std::any_of(layers.cbegin(), layers.cend(),
|
||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
||||
};
|
||||
|
||||
for (const auto &node : graph.nodes()) {
|
||||
for (const auto &snippet : node.rule(format).headerSnippets) {
|
||||
code << replaceParameters(snippet, node, format);
|
||||
if (intersectsEnabledLayers(node.layers())) {
|
||||
for (const auto &snippet : node.rule(format).headerSnippets) {
|
||||
code << replaceParameters(snippet, node, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +321,7 @@ QByteArray QShaderGenerator::createShaderCode() const
|
||||
code << QByteArrayLiteral("void main()");
|
||||
code << QByteArrayLiteral("{");
|
||||
|
||||
for (const auto &statement : graph.createStatements()) {
|
||||
for (const auto &statement : graph.createStatements(enabledLayers)) {
|
||||
const auto node = statement.node;
|
||||
auto line = node.rule(format).substitution;
|
||||
for (const auto &port : node.ports()) {
|
||||
|
@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
|
||||
class QShaderGenerator
|
||||
{
|
||||
public:
|
||||
Q_GUI_EXPORT QByteArray createShaderCode() const;
|
||||
Q_GUI_EXPORT QByteArray createShaderCode(const QStringList &enabledLayers = QStringList()) const;
|
||||
|
||||
QShaderGraph graph;
|
||||
QShaderFormat format;
|
||||
|
@ -51,23 +51,26 @@ namespace
|
||||
return port;
|
||||
}
|
||||
|
||||
QShaderNode createNode(const QVector<QShaderNodePort> &ports)
|
||||
QShaderNode createNode(const QVector<QShaderNodePort> &ports, const QStringList &layers = QStringList())
|
||||
{
|
||||
auto node = QShaderNode();
|
||||
node.setUuid(QUuid::createUuid());
|
||||
node.setLayers(layers);
|
||||
for (const auto &port : ports)
|
||||
node.addPort(port);
|
||||
return node;
|
||||
}
|
||||
|
||||
QShaderGraph::Edge createEdge(const QUuid &sourceUuid, const QString &sourceName,
|
||||
const QUuid &targetUuid, const QString &targetName)
|
||||
const QUuid &targetUuid, const QString &targetName,
|
||||
const QStringList &layers = QStringList())
|
||||
{
|
||||
auto edge = QShaderGraph::Edge();
|
||||
edge.sourceNodeUuid = sourceUuid;
|
||||
edge.sourcePortName = sourceName;
|
||||
edge.targetNodeUuid = targetUuid;
|
||||
edge.targetPortName = targetName;
|
||||
edge.layers = layers;
|
||||
return edge;
|
||||
}
|
||||
|
||||
@ -190,6 +193,7 @@ private slots:
|
||||
void shouldGenerateVersionCommands();
|
||||
void shouldProcessLanguageQualifierAndTypeEnums_data();
|
||||
void shouldProcessLanguageQualifierAndTypeEnums();
|
||||
void shouldGenerateDifferentCodeDependingOnActiveLayers();
|
||||
};
|
||||
|
||||
void tst_QShaderGenerator::shouldHaveDefaultState()
|
||||
@ -707,6 +711,185 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums()
|
||||
QCOMPARE(code, expectedCode);
|
||||
}
|
||||
|
||||
void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
|
||||
{
|
||||
// GIVEN
|
||||
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
|
||||
|
||||
auto texCoord = createNode({
|
||||
createPort(QShaderNodePort::Output, "texCoord")
|
||||
}, {
|
||||
"diffuseTexture",
|
||||
"normalTexture"
|
||||
});
|
||||
texCoord.addRule(gl4, QShaderNode::Rule("vec2 $texCoord = texCoord;",
|
||||
QByteArrayList() << "in vec2 texCoord;"));
|
||||
auto diffuseUniform = createNode({
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
}, {"diffuseUniform"});
|
||||
diffuseUniform.addRule(gl4, QShaderNode::Rule("vec4 $color = diffuseUniform;",
|
||||
QByteArrayList() << "uniform vec4 diffuseUniform;"));
|
||||
auto diffuseTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
}, {"diffuseTexture"});
|
||||
diffuseTexture.addRule(gl4, QShaderNode::Rule("vec4 $color = texture2D(diffuseTexture, $coord);",
|
||||
QByteArrayList() << "uniform sampler2D diffuseTexture;"));
|
||||
auto normalUniform = createNode({
|
||||
createPort(QShaderNodePort::Output, "normal")
|
||||
}, {"normalUniform"});
|
||||
normalUniform.addRule(gl4, QShaderNode::Rule("vec3 $normal = normalUniform;",
|
||||
QByteArrayList() << "uniform vec3 normalUniform;"));
|
||||
auto normalTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "normal")
|
||||
}, {"normalTexture"});
|
||||
normalTexture.addRule(gl4, QShaderNode::Rule("vec3 $normal = texture2D(normalTexture, $coord).rgb;",
|
||||
QByteArrayList() << "uniform sampler2D normalTexture;"));
|
||||
auto lightFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "color"),
|
||||
createPort(QShaderNodePort::Input, "normal"),
|
||||
createPort(QShaderNodePort::Output, "output")
|
||||
});
|
||||
lightFunction.addRule(gl4, QShaderNode::Rule("vec4 $output = lightModel($color, $normal);",
|
||||
QByteArrayList() << "#pragma include gl4/lightmodel.frag.inc"));
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.addRule(gl4, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
|
||||
res.addNode(texCoord);
|
||||
res.addNode(diffuseUniform);
|
||||
res.addNode(diffuseTexture);
|
||||
res.addNode(normalUniform);
|
||||
res.addNode(normalTexture);
|
||||
res.addNode(lightFunction);
|
||||
res.addNode(fragColor);
|
||||
|
||||
res.addEdge(createEdge(diffuseUniform.uuid(), "color", lightFunction.uuid(), "color", {"diffuseUniform"}));
|
||||
res.addEdge(createEdge(texCoord.uuid(), "texCoord", diffuseTexture.uuid(), "coord", {"diffuseTexture"}));
|
||||
res.addEdge(createEdge(diffuseTexture.uuid(), "color", lightFunction.uuid(), "color", {"diffuseTexture"}));
|
||||
|
||||
res.addEdge(createEdge(normalUniform.uuid(), "normal", lightFunction.uuid(), "normal", {"normalUniform"}));
|
||||
res.addEdge(createEdge(texCoord.uuid(), "texCoord", normalTexture.uuid(), "coord", {"normalTexture"}));
|
||||
res.addEdge(createEdge(normalTexture.uuid(), "normal", lightFunction.uuid(), "normal", {"normalTexture"}));
|
||||
|
||||
res.addEdge(createEdge(lightFunction.uuid(), "output", fragColor.uuid(), "fragColor"));
|
||||
|
||||
return res;
|
||||
}();
|
||||
|
||||
auto generator = QShaderGenerator();
|
||||
generator.graph = graph;
|
||||
generator.format = gl4;
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto code = generator.createShaderCode({"diffuseUniform", "normalUniform"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QByteArrayList()
|
||||
<< "#version 400 core"
|
||||
<< ""
|
||||
<< "uniform vec4 diffuseUniform;"
|
||||
<< "uniform vec3 normalUniform;"
|
||||
<< "#pragma include gl4/lightmodel.frag.inc"
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< " vec3 v1 = normalUniform;"
|
||||
<< " vec4 v0 = diffuseUniform;"
|
||||
<< " vec4 v2 = lightModel(v0, v1);"
|
||||
<< " fragColor = v2;"
|
||||
<< "}"
|
||||
<< "";
|
||||
QCOMPARE(code, expected.join("\n"));
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto code = generator.createShaderCode({"diffuseUniform", "normalTexture"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QByteArrayList()
|
||||
<< "#version 400 core"
|
||||
<< ""
|
||||
<< "in vec2 texCoord;"
|
||||
<< "uniform vec4 diffuseUniform;"
|
||||
<< "uniform sampler2D normalTexture;"
|
||||
<< "#pragma include gl4/lightmodel.frag.inc"
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< " vec2 v0 = texCoord;"
|
||||
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;"
|
||||
<< " vec4 v1 = diffuseUniform;"
|
||||
<< " vec4 v3 = lightModel(v1, v2);"
|
||||
<< " fragColor = v3;"
|
||||
<< "}"
|
||||
<< "";
|
||||
QCOMPARE(code, expected.join("\n"));
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto code = generator.createShaderCode({"diffuseTexture", "normalUniform"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QByteArrayList()
|
||||
<< "#version 400 core"
|
||||
<< ""
|
||||
<< "in vec2 texCoord;"
|
||||
<< "uniform sampler2D diffuseTexture;"
|
||||
<< "uniform vec3 normalUniform;"
|
||||
<< "#pragma include gl4/lightmodel.frag.inc"
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< " vec2 v0 = texCoord;"
|
||||
<< " vec3 v2 = normalUniform;"
|
||||
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
|
||||
<< " vec4 v3 = lightModel(v1, v2);"
|
||||
<< " fragColor = v3;"
|
||||
<< "}"
|
||||
<< "";
|
||||
QCOMPARE(code, expected.join("\n"));
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto code = generator.createShaderCode({"diffuseTexture", "normalTexture"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QByteArrayList()
|
||||
<< "#version 400 core"
|
||||
<< ""
|
||||
<< "in vec2 texCoord;"
|
||||
<< "uniform sampler2D diffuseTexture;"
|
||||
<< "uniform sampler2D normalTexture;"
|
||||
<< "#pragma include gl4/lightmodel.frag.inc"
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< " vec2 v0 = texCoord;"
|
||||
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;"
|
||||
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
|
||||
<< " vec4 v3 = lightModel(v1, v2);"
|
||||
<< " fragColor = v3;"
|
||||
<< "}"
|
||||
<< "";
|
||||
QCOMPARE(code, expected.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QShaderGenerator)
|
||||
|
||||
#include "tst_qshadergenerator.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user