summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Guichard <nicolas.guichard@kdab.com>2020-07-30 12:51:40 +0200
committerNicolas Guichard <nicolas.guichard@kdab.com>2020-07-31 16:40:32 +0200
commitb865079dc5b0910f5277deceda44adfc3af3c522 (patch)
treeac82984eb82852e167fd522201240d503850b5d8
parentf70072bf20418ac8b4d87408cf1b9be58e0e7195 (diff)
QShaderGenerator: generate node headers in the same order as statements
This ensures that header snippets that depend on one another are forced to be emitted in the correct order, assuming the nodes also depend on one another. This has the side effect of dropping header snippets from nodes which are not connected to any output node or with any unbound input. Also removed a few lines of unused code. Change-Id: I5e544470aea1d34467f8165fb49e48d38931e0bc Reviewed-by: Paul Lemire <paul.lemire@kdab.com> (cherry picked from commit 0ee455a025b21c06f99c41cba5a699a4a1bc78c8)
-rw-r--r--src/render/shadergraph/qshadergenerator.cpp86
-rw-r--r--tests/auto/render/shaderbuilder/output.es24
-rw-r--r--tests/auto/render/shaderbuilder/output.gl310
-rw-r--r--tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp153
4 files changed, 111 insertions, 142 deletions
diff --git a/src/render/shadergraph/qshadergenerator.cpp b/src/render/shadergraph/qshadergenerator.cpp
index 92c69be72..f80502fcc 100644
--- a/src/render/shadergraph/qshadergenerator.cpp
+++ b/src/render/shadergraph/qshadergenerator.cpp
@@ -295,30 +295,18 @@ namespace
return result;
}
- bool intersectsEnabledLayers(const QStringList &enabledLayers, const QStringList &layers) noexcept
- {
- return layers.isEmpty()
- || std::any_of(layers.cbegin(), layers.cend(),
- [enabledLayers](const QString &s) { return enabledLayers.contains(s); });
- }
-
struct ShaderGenerationState
{
- ShaderGenerationState(const QShaderGenerator & gen, QStringList layers, QVector<QShaderNode> nodes)
- : generator{gen}
- , enabledLayers{layers}
- , nodes{nodes}
+ ShaderGenerationState(const QShaderGenerator &gen,
+ QVector<QShaderGraph::Statement> statements)
+ : generator { gen }, statements { statements }
{
}
const QShaderGenerator &generator;
- QStringList enabledLayers;
- QVector<QShaderNode> nodes;
+ QVector<QShaderGraph::Statement> statements;
QByteArrayList code;
-
- QVector<QString> globalInputVariables;
- const QRegularExpression globalInputExtractRegExp { QStringLiteral("^.*\\s+(\\w+).*;$") };
};
class GLSL45HeaderWriter
@@ -328,31 +316,22 @@ namespace
{
const auto &format = state.generator.format;
auto &code = state.code;
- for (const QShaderNode &node : state.nodes) {
- if (intersectsEnabledLayers(state.enabledLayers, node.layers())) {
- const QByteArrayList& headerSnippets = node.rule(format).headerSnippets;
- for (const QByteArray &snippet : headerSnippets) {
- auto replacedSnippet = replaceParameters(snippet, node, format).trimmed();
-
- if (replacedSnippet.startsWith(QByteArrayLiteral("add-input"))) {
- onInOut(code, replacedSnippet);
- } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-uniform"))) {
- onNamedUniform(ubo, replacedSnippet);
- } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-sampler"))) {
- onNamedSampler(code, replacedSnippet);
- } else if (replacedSnippet.startsWith(QByteArrayLiteral("#pragma include "))) {
- onInclude(code, replacedSnippet);
- } else {
- code << replacedSnippet;
- }
- // If node is an input, record the variable name into the globalInputVariables
- // vector
- if (node.type() == QShaderNode::Input) {
- const QRegularExpressionMatch match = state.globalInputExtractRegExp.match(
- QString::fromUtf8(code.last()));
- if (match.hasMatch())
- state.globalInputVariables.push_back(match.captured(1));
- }
+ for (const QShaderGraph::Statement &statement : state.statements) {
+ const QShaderNode &node = statement.node;
+ const QByteArrayList &headerSnippets = node.rule(format).headerSnippets;
+ for (const QByteArray &snippet : headerSnippets) {
+ auto replacedSnippet = replaceParameters(snippet, node, format).trimmed();
+
+ if (replacedSnippet.startsWith(QByteArrayLiteral("add-input"))) {
+ onInOut(code, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-uniform"))) {
+ onNamedUniform(ubo, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-sampler"))) {
+ onNamedSampler(code, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("#pragma include "))) {
+ onInclude(code, replacedSnippet);
+ } else {
+ code << replacedSnippet;
}
}
}
@@ -483,21 +462,11 @@ namespace
{
const auto &format = state.generator.format;
auto &code = state.code;
- for (const QShaderNode &node : state.nodes) {
- if (intersectsEnabledLayers(state.enabledLayers, 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 = state.globalInputExtractRegExp.match(
- QString::fromUtf8(code.last()));
- if (match.hasMatch())
- state.globalInputVariables.push_back(match.captured(1));
- }
- }
+ for (const QShaderGraph::Statement &statement : state.statements) {
+ const QShaderNode &node = statement.node;
+ const QByteArrayList &headerSnippets = node.rule(format).headerSnippets;
+ for (const QByteArray &snippet : headerSnippets) {
+ code << replaceParameters(snippet, node, format);
}
}
}
@@ -543,7 +512,8 @@ namespace
QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
{
const QVector<QShaderNode> nodes = graph.nodes();
- ShaderGenerationState state(*this, enabledLayers, nodes);
+ const auto statements = graph.createStatements(enabledLayers);
+ ShaderGenerationState state(*this, statements);
QByteArrayList &code = state.code;
code << versionString(format);
@@ -670,7 +640,7 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
}
};
- for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
+ for (const QShaderGraph::Statement &statement : statements) {
const QShaderNode node = statement.node;
QByteArray line = node.rule(format).substitution;
const QVector<QShaderNodePort> ports = node.ports();
diff --git a/tests/auto/render/shaderbuilder/output.es2 b/tests/auto/render/shaderbuilder/output.es2
index 0298e7e51..ce0413614 100644
--- a/tests/auto/render/shaderbuilder/output.es2
+++ b/tests/auto/render/shaderbuilder/output.es2
@@ -1,9 +1,9 @@
#version 100
-varying highp vec3 worldPosition;
-uniform sampler2D texture;
varying highp vec2 texCoord;
+uniform sampler2D texture;
uniform highp float lightIntensity;
+varying highp vec3 worldPosition;
uniform highp float exposure;
highp vec4 lightModel(const in highp vec3 baseColor,
const in highp vec3 pos,
diff --git a/tests/auto/render/shaderbuilder/output.gl3 b/tests/auto/render/shaderbuilder/output.gl3
index 4c9fd1064..e0951deee 100644
--- a/tests/auto/render/shaderbuilder/output.gl3
+++ b/tests/auto/render/shaderbuilder/output.gl3
@@ -1,11 +1,10 @@
#version 150 core
-in vec3 worldPosition;
-uniform sampler2D texture;
in vec2 texCoord;
+uniform sampler2D texture;
uniform float lightIntensity;
+in vec3 worldPosition;
uniform float exposure;
-out vec4 fragColor;
vec4 lightModel(const in vec3 baseColor,
const in vec3 pos,
const in float intensity)
@@ -13,7 +12,7 @@ vec4 lightModel(const in vec3 baseColor,
...
}
-#line 10
+#line 9
vec4 lightModel(const in vec3 baseColor,
const in vec3 pos,
const in float intensity)
@@ -21,7 +20,8 @@ vec4 lightModel(const in vec3 baseColor,
...
}
-#line 12
+#line 11
+out vec4 fragColor;
void main()
{
diff --git a/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
index 90906f4e9..e386ae09f 100644
--- a/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
+++ b/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
@@ -233,32 +233,36 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
const auto versionGL32 = QByteArrayList() << "#version 150 core" << "";
const auto versionGL4 = QByteArrayList() << "#version 400 core" << "";
- const auto es2Code = QByteArrayList() << "varying highp vec3 worldPosition;"
- << "uniform sampler2D texture;"
- << "varying highp vec2 texCoord;"
- << "uniform highp float lightIntensity;"
- << "uniform highp float exposure;"
- << "#pragma include es2/lightmodel.frag.inc"
- << ""
- << "void main()"
- << "{"
- << " gl_fragColor = (((((lightModel(((texture2D(texture, texCoord))), worldPosition, lightIntensity)))) * pow(2.0, exposure)));"
- << "}"
- << "";
-
- const auto gl3Code = QByteArrayList() << "in vec3 worldPosition;"
- << "uniform sampler2D texture;"
- << "in vec2 texCoord;"
- << "uniform float lightIntensity;"
- << "uniform float exposure;"
- << "out vec4 fragColor;"
- << "#pragma include gl3/lightmodel.frag.inc"
- << ""
- << "void main()"
- << "{"
- << " fragColor = (((((lightModel(((texture(texture, texCoord))), worldPosition, lightIntensity)))) * pow(2.0, exposure)));"
- << "}"
- << "";
+ const auto es2Code = QByteArrayList()
+ << "varying highp vec2 texCoord;"
+ << "uniform sampler2D texture;"
+ << "uniform highp float lightIntensity;"
+ << "varying highp vec3 worldPosition;"
+ << "uniform highp float exposure;"
+ << "#pragma include es2/lightmodel.frag.inc"
+ << ""
+ << "void main()"
+ << "{"
+ << " gl_fragColor = (((((lightModel(((texture2D(texture, texCoord))), "
+ "worldPosition, lightIntensity)))) * pow(2.0, exposure)));"
+ << "}"
+ << "";
+
+ const auto gl3Code = QByteArrayList()
+ << "in vec2 texCoord;"
+ << "uniform sampler2D texture;"
+ << "uniform float lightIntensity;"
+ << "in vec3 worldPosition;"
+ << "uniform float exposure;"
+ << "#pragma include gl3/lightmodel.frag.inc"
+ << "out vec4 fragColor;"
+ << ""
+ << "void main()"
+ << "{"
+ << " fragColor = (((((lightModel(((texture(texture, texCoord))), worldPosition, "
+ "lightIntensity)))) * pow(2.0, exposure)));"
+ << "}"
+ << "";
QTest::newRow("EmptyGraphAndFormat") << QShaderGraph() << QShaderFormat() << QByteArrayLiteral("\n\n\nvoid main()\n{\n}\n");
QTest::newRow("LightExposureGraphAndES2") << graph << openGLES2 << (versionGLES2 + es2Code).join('\n');
@@ -712,7 +716,6 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
const auto gl2Code = (QByteArrayList() << "#version 110"
<< ""
- << "attribute vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
@@ -720,7 +723,6 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< "").join("\n");
const auto gl3Code = (QByteArrayList() << "#version 130"
<< ""
- << "in vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
@@ -728,7 +730,6 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< "").join("\n");
const auto gl4Code = (QByteArrayList() << "#version 400 core"
<< ""
- << "in vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
@@ -736,7 +737,6 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< "").join("\n");
const auto es2Code = (QByteArrayList() << "#version 100"
<< ""
- << "attribute highp vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
@@ -744,7 +744,6 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< "").join("\n");
const auto es3Code = (QByteArrayList() << "#version 300 es"
<< ""
- << "in highp vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
@@ -861,8 +860,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
const auto expected = QByteArrayList()
<< "#version 400 core"
<< ""
- << "uniform vec4 diffuseUniform;"
<< "uniform vec3 normalUniform;"
+ << "uniform vec4 diffuseUniform;"
<< "#pragma include gl4/lightmodel.frag.inc"
<< "out vec4 fragColor;"
<< ""
@@ -879,20 +878,20 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
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()"
- << "{"
- << " fragColor = ((lightModel(diffuseUniform, texture2D(normalTexture, texCoord).rgb)));"
- << "}"
- << "";
+ const auto expected = QByteArrayList() << "#version 400 core"
+ << ""
+ << "in vec2 texCoord;"
+ << "uniform sampler2D normalTexture;"
+ << "uniform vec4 diffuseUniform;"
+ << "#pragma include gl4/lightmodel.frag.inc"
+ << "out vec4 fragColor;"
+ << ""
+ << "void main()"
+ << "{"
+ << " fragColor = ((lightModel(diffuseUniform, "
+ "texture2D(normalTexture, texCoord).rgb)));"
+ << "}"
+ << "";
QCOMPARE(code, expected.join("\n"));
}
@@ -905,14 +904,15 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "#version 400 core"
<< ""
<< "in vec2 texCoord;"
- << "uniform sampler2D diffuseTexture;"
<< "uniform vec3 normalUniform;"
+ << "uniform sampler2D diffuseTexture;"
<< "#pragma include gl4/lightmodel.frag.inc"
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
- << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), normalUniform)));"
+ << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), "
+ "normalUniform)));"
<< "}"
<< "";
QCOMPARE(code, expected.join("\n"));
@@ -927,14 +927,15 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "#version 400 core"
<< ""
<< "in vec2 texCoord;"
- << "uniform sampler2D diffuseTexture;"
<< "uniform sampler2D normalTexture;"
+ << "uniform sampler2D diffuseTexture;"
<< "#pragma include gl4/lightmodel.frag.inc"
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
- << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), texture2D(normalTexture, texCoord).rgb)));"
+ << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), "
+ "texture2D(normalTexture, texCoord).rgb)));"
<< "}"
<< "";
QCOMPARE(code, expected.join("\n"));
@@ -1166,20 +1167,19 @@ void tst_QShaderGenerator::shouldGenerateTemporariesWisely()
const auto code = generator.createShaderCode();
// THEN
- const auto expected = QByteArrayList()
- << "#version 400 core"
- << ""
- << "in vec4 vertexPosition;"
- << "out vec4 shaderOutput1;"
- << "out vec4 shaderOutput2;"
- << ""
- << "void main()"
- << "{"
- << " vec4 v1 = vertexPosition * 2.0;"
- << " shaderOutput2 = v1;"
- << " shaderOutput1 = v1;"
- << "}"
- << "";
+ const auto expected = QByteArrayList() << "#version 400 core"
+ << ""
+ << "in vec4 vertexPosition;"
+ << "out vec4 shaderOutput2;"
+ << "out vec4 shaderOutput1;"
+ << ""
+ << "void main()"
+ << "{"
+ << " vec4 v1 = vertexPosition * 2.0;"
+ << " shaderOutput2 = v1;"
+ << " shaderOutput1 = v1;"
+ << "}"
+ << "";
QCOMPARE(code, expected.join("\n"));
}
@@ -1218,8 +1218,8 @@ void tst_QShaderGenerator::shouldGenerateTemporariesWisely()
<< "#version 400 core"
<< ""
<< "in vec4 vertexPosition;"
- << "out vec4 shaderOutput1;"
<< "out vec4 shaderOutput2;"
+ << "out vec4 shaderOutput1;"
<< ""
<< "void main()"
<< "{"
@@ -1287,18 +1287,17 @@ void tst_QShaderGenerator::shouldHandlePortNamesPrefixingOneAnother()
const auto code = generator.createShaderCode();
// THEN
- const auto expected = QByteArrayList()
- << "#version 400 core"
- << ""
- << "in vec4 color1;"
- << "in vec4 color2;"
- << "out vec4 shaderOutput;"
- << ""
- << "void main()"
- << "{"
- << " shaderOutput = ((color1 + color2));"
- << "}"
- << "";
+ const auto expected = QByteArrayList() << "#version 400 core"
+ << ""
+ << "in vec4 color2;"
+ << "in vec4 color1;"
+ << "out vec4 shaderOutput;"
+ << ""
+ << "void main()"
+ << "{"
+ << " shaderOutput = ((color1 + color2));"
+ << "}"
+ << "";
QCOMPARE(code, expected.join("\n"));
}