595 lines
24 KiB
C++
595 lines
24 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the QtGui module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 2.0 or (at your option) the GNU General
|
|
** Public license version 3 or any later version approved by the KDE Free
|
|
** Qt Foundation. The licenses are as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qshadergenerator_p.h"
|
|
|
|
#include "qshaderlanguage_p.h"
|
|
#include <QRegularExpression>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg)
|
|
|
|
namespace
|
|
{
|
|
QByteArray toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format)
|
|
{
|
|
if (format.version().majorVersion() <= 2) {
|
|
// Note we're assuming fragment shader only here, it'd be different
|
|
// values for vertex shader, will need to be fixed properly at some
|
|
// point but isn't necessary yet (this problem already exists in past
|
|
// commits anyway)
|
|
switch (qualifier) {
|
|
case QShaderLanguage::Const:
|
|
return "const";
|
|
case QShaderLanguage::Input:
|
|
if (format.shaderType() == QShaderFormat::Vertex)
|
|
return "attribute";
|
|
else
|
|
return "varying";
|
|
case QShaderLanguage::Output:
|
|
return ""; // Although fragment shaders for <=2 only have fixed outputs
|
|
case QShaderLanguage::Uniform:
|
|
return "uniform";
|
|
case QShaderLanguage::BuiltIn:
|
|
return "//";
|
|
}
|
|
} else {
|
|
switch (qualifier) {
|
|
case QShaderLanguage::Const:
|
|
return "const";
|
|
case QShaderLanguage::Input:
|
|
return "in";
|
|
case QShaderLanguage::Output:
|
|
return "out";
|
|
case QShaderLanguage::Uniform:
|
|
return "uniform";
|
|
case QShaderLanguage::BuiltIn:
|
|
return "//";
|
|
}
|
|
}
|
|
|
|
Q_UNREACHABLE();
|
|
}
|
|
|
|
QByteArray toGlsl(QShaderLanguage::VariableType type)
|
|
{
|
|
switch (type) {
|
|
case QShaderLanguage::Bool:
|
|
return "bool";
|
|
case QShaderLanguage::Int:
|
|
return "int";
|
|
case QShaderLanguage::Uint:
|
|
return "uint";
|
|
case QShaderLanguage::Float:
|
|
return "float";
|
|
case QShaderLanguage::Double:
|
|
return "double";
|
|
case QShaderLanguage::Vec2:
|
|
return "vec2";
|
|
case QShaderLanguage::Vec3:
|
|
return "vec3";
|
|
case QShaderLanguage::Vec4:
|
|
return "vec4";
|
|
case QShaderLanguage::DVec2:
|
|
return "dvec2";
|
|
case QShaderLanguage::DVec3:
|
|
return "dvec3";
|
|
case QShaderLanguage::DVec4:
|
|
return "dvec4";
|
|
case QShaderLanguage::BVec2:
|
|
return "bvec2";
|
|
case QShaderLanguage::BVec3:
|
|
return "bvec3";
|
|
case QShaderLanguage::BVec4:
|
|
return "bvec4";
|
|
case QShaderLanguage::IVec2:
|
|
return "ivec2";
|
|
case QShaderLanguage::IVec3:
|
|
return "ivec3";
|
|
case QShaderLanguage::IVec4:
|
|
return "ivec4";
|
|
case QShaderLanguage::UVec2:
|
|
return "uvec2";
|
|
case QShaderLanguage::UVec3:
|
|
return "uvec3";
|
|
case QShaderLanguage::UVec4:
|
|
return "uvec4";
|
|
case QShaderLanguage::Mat2:
|
|
return "mat2";
|
|
case QShaderLanguage::Mat3:
|
|
return "mat3";
|
|
case QShaderLanguage::Mat4:
|
|
return "mat4";
|
|
case QShaderLanguage::Mat2x2:
|
|
return "mat2x2";
|
|
case QShaderLanguage::Mat2x3:
|
|
return "mat2x3";
|
|
case QShaderLanguage::Mat2x4:
|
|
return "mat2x4";
|
|
case QShaderLanguage::Mat3x2:
|
|
return "mat3x2";
|
|
case QShaderLanguage::Mat3x3:
|
|
return "mat3x3";
|
|
case QShaderLanguage::Mat3x4:
|
|
return "mat3x4";
|
|
case QShaderLanguage::Mat4x2:
|
|
return "mat4x2";
|
|
case QShaderLanguage::Mat4x3:
|
|
return "mat4x3";
|
|
case QShaderLanguage::Mat4x4:
|
|
return "mat4x4";
|
|
case QShaderLanguage::DMat2:
|
|
return "dmat2";
|
|
case QShaderLanguage::DMat3:
|
|
return "dmat3";
|
|
case QShaderLanguage::DMat4:
|
|
return "dmat4";
|
|
case QShaderLanguage::DMat2x2:
|
|
return "dmat2x2";
|
|
case QShaderLanguage::DMat2x3:
|
|
return "dmat2x3";
|
|
case QShaderLanguage::DMat2x4:
|
|
return "dmat2x4";
|
|
case QShaderLanguage::DMat3x2:
|
|
return "dmat3x2";
|
|
case QShaderLanguage::DMat3x3:
|
|
return "dmat3x3";
|
|
case QShaderLanguage::DMat3x4:
|
|
return "dmat3x4";
|
|
case QShaderLanguage::DMat4x2:
|
|
return "dmat4x2";
|
|
case QShaderLanguage::DMat4x3:
|
|
return "dmat4x3";
|
|
case QShaderLanguage::DMat4x4:
|
|
return "dmat4x4";
|
|
case QShaderLanguage::Sampler1D:
|
|
return "sampler1D";
|
|
case QShaderLanguage::Sampler2D:
|
|
return "sampler2D";
|
|
case QShaderLanguage::Sampler3D:
|
|
return "sampler3D";
|
|
case QShaderLanguage::SamplerCube:
|
|
return "samplerCube";
|
|
case QShaderLanguage::Sampler2DRect:
|
|
return "sampler2DRect";
|
|
case QShaderLanguage::Sampler2DMs:
|
|
return "sampler2DMS";
|
|
case QShaderLanguage::SamplerBuffer:
|
|
return "samplerBuffer";
|
|
case QShaderLanguage::Sampler1DArray:
|
|
return "sampler1DArray";
|
|
case QShaderLanguage::Sampler2DArray:
|
|
return "sampler2DArray";
|
|
case QShaderLanguage::Sampler2DMsArray:
|
|
return "sampler2DMSArray";
|
|
case QShaderLanguage::SamplerCubeArray:
|
|
return "samplerCubeArray";
|
|
case QShaderLanguage::Sampler1DShadow:
|
|
return "sampler1DShadow";
|
|
case QShaderLanguage::Sampler2DShadow:
|
|
return "sampler2DShadow";
|
|
case QShaderLanguage::Sampler2DRectShadow:
|
|
return "sampler2DRectShadow";
|
|
case QShaderLanguage::Sampler1DArrayShadow:
|
|
return "sampler1DArrayShadow";
|
|
case QShaderLanguage::Sampler2DArrayShadow:
|
|
return "sample2DArrayShadow";
|
|
case QShaderLanguage::SamplerCubeShadow:
|
|
return "samplerCubeShadow";
|
|
case QShaderLanguage::SamplerCubeArrayShadow:
|
|
return "samplerCubeArrayShadow";
|
|
case QShaderLanguage::ISampler1D:
|
|
return "isampler1D";
|
|
case QShaderLanguage::ISampler2D:
|
|
return "isampler2D";
|
|
case QShaderLanguage::ISampler3D:
|
|
return "isampler3D";
|
|
case QShaderLanguage::ISamplerCube:
|
|
return "isamplerCube";
|
|
case QShaderLanguage::ISampler2DRect:
|
|
return "isampler2DRect";
|
|
case QShaderLanguage::ISampler2DMs:
|
|
return "isampler2DMS";
|
|
case QShaderLanguage::ISamplerBuffer:
|
|
return "isamplerBuffer";
|
|
case QShaderLanguage::ISampler1DArray:
|
|
return "isampler1DArray";
|
|
case QShaderLanguage::ISampler2DArray:
|
|
return "isampler2DArray";
|
|
case QShaderLanguage::ISampler2DMsArray:
|
|
return "isampler2DMSArray";
|
|
case QShaderLanguage::ISamplerCubeArray:
|
|
return "isamplerCubeArray";
|
|
case QShaderLanguage::USampler1D:
|
|
return "usampler1D";
|
|
case QShaderLanguage::USampler2D:
|
|
return "usampler2D";
|
|
case QShaderLanguage::USampler3D:
|
|
return "usampler3D";
|
|
case QShaderLanguage::USamplerCube:
|
|
return "usamplerCube";
|
|
case QShaderLanguage::USampler2DRect:
|
|
return "usampler2DRect";
|
|
case QShaderLanguage::USampler2DMs:
|
|
return "usampler2DMS";
|
|
case QShaderLanguage::USamplerBuffer:
|
|
return "usamplerBuffer";
|
|
case QShaderLanguage::USampler1DArray:
|
|
return "usampler1DArray";
|
|
case QShaderLanguage::USampler2DArray:
|
|
return "usampler2DArray";
|
|
case QShaderLanguage::USampler2DMsArray:
|
|
return "usampler2DMSArray";
|
|
case QShaderLanguage::USamplerCubeArray:
|
|
return "usamplerCubeArray";
|
|
}
|
|
|
|
Q_UNREACHABLE();
|
|
}
|
|
|
|
QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
|
|
{
|
|
QByteArray result = original;
|
|
|
|
const QStringList parameterNames = node.parameterNames();
|
|
for (const QString ¶meterName : parameterNames) {
|
|
const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
|
|
const QVariant parameter = node.parameter(parameterName);
|
|
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
|
|
const QShaderLanguage::StorageQualifier qualifier = qvariant_cast<QShaderLanguage::StorageQualifier>(parameter);
|
|
const QByteArray value = toGlsl(qualifier, format);
|
|
result.replace(placeholder, value);
|
|
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
|
|
const QShaderLanguage::VariableType type = qvariant_cast<QShaderLanguage::VariableType>(parameter);
|
|
const QByteArray value = toGlsl(type);
|
|
result.replace(placeholder, value);
|
|
} else {
|
|
const QByteArray value = parameter.toString().toUtf8();
|
|
result.replace(placeholder, value);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
|
|
{
|
|
auto code = QByteArrayList();
|
|
|
|
if (format.isValid()) {
|
|
const bool isGLES = format.api() == QShaderFormat::OpenGLES;
|
|
const int major = format.version().majorVersion();
|
|
const int minor = format.version().minorVersion();
|
|
|
|
const int version = major == 2 && isGLES ? 100
|
|
: major == 3 && isGLES ? 300
|
|
: major == 2 ? 100 + 10 * (minor + 1)
|
|
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
|
|
: major * 100 + minor * 10;
|
|
|
|
const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
|
|
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
|
|
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
|
|
: QByteArray();
|
|
|
|
code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
|
|
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); });
|
|
};
|
|
|
|
QVector<QString> globalInputVariables;
|
|
const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$"));
|
|
|
|
const QVector<QShaderNode> nodes = graph.nodes();
|
|
for (const QShaderNode &node : nodes) {
|
|
if (intersectsEnabledLayers(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 = globalInputExtractRegExp.match(QString::fromUtf8(code.last()));
|
|
if (match.hasMatch())
|
|
globalInputVariables.push_back(match.captured(1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
code << QByteArray();
|
|
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*(.*);$"));
|
|
|
|
struct Variable;
|
|
|
|
struct Assignment
|
|
{
|
|
QString expression;
|
|
QVector<Variable *> referencedVariables;
|
|
};
|
|
|
|
struct Variable
|
|
{
|
|
enum Type {
|
|
GlobalInput,
|
|
TemporaryAssignment,
|
|
Output
|
|
};
|
|
|
|
QString name;
|
|
QString declaration;
|
|
int referenceCount = 0;
|
|
Assignment assignment;
|
|
Type type = TemporaryAssignment;
|
|
bool substituted = false;
|
|
|
|
static void substitute(Variable *v)
|
|
{
|
|
if (v->substituted)
|
|
return;
|
|
|
|
qCDebug(ShaderGenerator) << "Begin Substituting " << v->name << " = " << v->assignment.expression;
|
|
for (Variable *ref : qAsConst(v->assignment.referencedVariables)) {
|
|
// Recursively substitute
|
|
Variable::substitute(ref);
|
|
|
|
// Replace all variables referenced only once in the assignment
|
|
// by their actual expression
|
|
if (ref->referenceCount == 1 || ref->type == Variable::GlobalInput) {
|
|
const QRegularExpression r(QStringLiteral("(.*\\b)(%1)(\\b.*)").arg(ref->name));
|
|
if (v->assignment.referencedVariables.size() == 1)
|
|
v->assignment.expression.replace(r,
|
|
QStringLiteral("\\1%2\\3").arg(ref->assignment.expression));
|
|
else
|
|
v->assignment.expression.replace(r,
|
|
QStringLiteral("(\\1%2\\3)").arg(ref->assignment.expression));
|
|
}
|
|
}
|
|
qCDebug(ShaderGenerator) << "Done Substituting " << v->name << " = " << v->assignment.expression;
|
|
v->substituted = true;
|
|
}
|
|
};
|
|
|
|
struct LineContent
|
|
{
|
|
QByteArray rawContent;
|
|
Variable *var = nullptr;
|
|
};
|
|
|
|
// Table to store temporary variables that should be replaced:
|
|
// - If variable references a a global variables
|
|
// -> we will use the global variable directly
|
|
// - If variable references a function results
|
|
// -> will be kept only if variable is referenced more than once.
|
|
// This avoids having vec3 v56 = vertexPosition; when we could
|
|
// just use vertexPosition directly.
|
|
// The added benefit is when having arrays, we don't try to create
|
|
// mat4 v38 = skinningPalelette[100] which would be invalid
|
|
QVector<Variable> temporaryVariables;
|
|
// Reserve more than enough space to ensure no reallocation will take place
|
|
temporaryVariables.reserve(nodes.size() * 8);
|
|
|
|
QVector<LineContent> lines;
|
|
|
|
auto createVariable = [&] () -> Variable * {
|
|
Q_ASSERT(temporaryVariables.capacity() > 0);
|
|
temporaryVariables.resize(temporaryVariables.size() + 1);
|
|
return &temporaryVariables.last();
|
|
};
|
|
|
|
auto findVariable = [&] (const QString &name) -> Variable * {
|
|
const auto end = temporaryVariables.end();
|
|
auto it = std::find_if(temporaryVariables.begin(), end,
|
|
[=] (const Variable &a) { return a.name == name; });
|
|
if (it != end)
|
|
return &(*it);
|
|
return nullptr;
|
|
};
|
|
|
|
auto gatherTemporaryVariablesFromAssignment = [&] (Variable *v, const QString &assignmentContent) {
|
|
QRegularExpressionMatchIterator subMatchIt = temporaryVariableInAssignmentRegExp.globalMatch(assignmentContent);
|
|
while (subMatchIt.hasNext()) {
|
|
const QRegularExpressionMatch subMatch = subMatchIt.next();
|
|
const QString variableName = subMatch.captured(1);
|
|
|
|
// Variable we care about should already exists -> an expression cannot reference a variable that hasn't been defined
|
|
Variable *u = findVariable(variableName);
|
|
Q_ASSERT(u);
|
|
|
|
// Increase reference count for u
|
|
++u->referenceCount;
|
|
// Insert u as reference for variable v
|
|
v->assignment.referencedVariables.push_back(u);
|
|
}
|
|
};
|
|
|
|
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
|
|
const QShaderNode node = statement.node;
|
|
QByteArray line = node.rule(format).substitution;
|
|
const QVector<QShaderNodePort> ports = node.ports();
|
|
|
|
// Generate temporary variable names vN
|
|
for (const QShaderNodePort &port : ports) {
|
|
const QString portName = port.name;
|
|
const QShaderNodePort::Direction portDirection = port.direction;
|
|
const bool isInput = port.direction == QShaderNodePort::Input;
|
|
|
|
const int portIndex = statement.portIndex(portDirection, portName);
|
|
|
|
Q_ASSERT(portIndex >= 0);
|
|
|
|
const int variableIndex = isInput ? statement.inputs.at(portIndex)
|
|
: statement.outputs.at(portIndex);
|
|
if (variableIndex < 0)
|
|
continue;
|
|
|
|
const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8());
|
|
const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex));
|
|
|
|
line.replace(placeholder, variable);
|
|
}
|
|
|
|
// Substitute variable names by generated vN variable names
|
|
const QByteArray substitutionedLine = replaceParameters(line, node, format);
|
|
|
|
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 QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine));
|
|
if (match.hasMatch()) {
|
|
const QString localVariable = match.captured(1);
|
|
const QString globalVariable = match.captured(2);
|
|
|
|
v = createVariable();
|
|
v->name = localVariable;
|
|
v->type = Variable::GlobalInput;
|
|
|
|
Assignment assignment;
|
|
assignment.expression = globalVariable;
|
|
v->assignment = assignment;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case QShaderNode::Function: {
|
|
const QRegularExpressionMatch match = temporaryVariableToAssignmentRegExp.match(QString::fromUtf8(substitutionedLine));
|
|
if (match.hasMatch()) {
|
|
const QString localVariableDeclaration = match.captured(1);
|
|
const QString localVariableName = match.captured(2);
|
|
const QString assignmentContent = match.captured(3);
|
|
|
|
// Add new variable -> it cannot exist already
|
|
v = createVariable();
|
|
v->name = localVariableName;
|
|
v->declaration = localVariableDeclaration;
|
|
v->assignment.expression = assignmentContent;
|
|
|
|
// Find variables that may be referenced in the assignment
|
|
gatherTemporaryVariablesFromAssignment(v, assignmentContent);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case QShaderNode::Output: {
|
|
const QRegularExpressionMatch match = outputToTemporaryAssignmentRegExp.match(QString::fromUtf8(substitutionedLine));
|
|
if (match.hasMatch()) {
|
|
const QString outputDeclaration = match.captured(1);
|
|
const QString assignmentContent = match.captured(2);
|
|
|
|
v = createVariable();
|
|
v->name = outputDeclaration;
|
|
v->declaration = outputDeclaration;
|
|
v->type = Variable::Output;
|
|
|
|
Assignment assignment;
|
|
assignment.expression = assignmentContent;
|
|
v->assignment = assignment;
|
|
|
|
// Find variables that may be referenced in the assignment
|
|
gatherTemporaryVariablesFromAssignment(v, assignmentContent);
|
|
}
|
|
break;
|
|
}
|
|
case QShaderNode::Invalid:
|
|
break;
|
|
}
|
|
|
|
LineContent lineContent;
|
|
lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine);
|
|
lineContent.var = v;
|
|
lines << lineContent;
|
|
}
|
|
|
|
// Go through all lines
|
|
// Perform substitution of line with temporary variables substitution
|
|
for (LineContent &lineContent : lines) {
|
|
Variable *v = lineContent.var;
|
|
qCDebug(ShaderGenerator) << lineContent.rawContent;
|
|
if (v != nullptr) {
|
|
Variable::substitute(v);
|
|
|
|
qCDebug(ShaderGenerator) << "Line " << lineContent.rawContent << "is assigned to temporary" << v->name;
|
|
|
|
// Check number of occurrences a temporary variable is referenced
|
|
if (v->referenceCount == 1 || v->type == Variable::GlobalInput) {
|
|
// If it is referenced only once, no point in creating a temporary
|
|
// Clear content for current line
|
|
lineContent.rawContent.clear();
|
|
// We assume expression that were referencing vN will have vN properly substituted
|
|
} else {
|
|
lineContent.rawContent = QStringLiteral(" %1 = %2;").arg(v->declaration)
|
|
.arg(v->assignment.expression)
|
|
.toUtf8();
|
|
}
|
|
|
|
qCDebug(ShaderGenerator) << "Updated Line is " << lineContent.rawContent;
|
|
}
|
|
}
|
|
|
|
// Go throug all lines and insert content
|
|
for (const LineContent &lineContent : qAsConst(lines)) {
|
|
if (!lineContent.rawContent.isEmpty()) {
|
|
code << lineContent.rawContent;
|
|
}
|
|
}
|
|
|
|
code << QByteArrayLiteral("}");
|
|
code << QByteArray();
|
|
|
|
return code.join('\n');
|
|
}
|
|
|
|
QT_END_NAMESPACE
|