QShaderGenerator: fix substitution for attributes on GL2/ES2
GL2/ES2 expect it to be attribute and not in like later versions of OpenGL. Task-number: QTBUG-74829 Change-Id: Iddd22386ed315d6e6843d8225e49a4b73b6ad9ba Reviewed-by: Sean Harmer <sean.harmer@kdab.com>bb10
parent
7c74048e94
commit
60181f13a3
|
|
@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
QShaderFormat::QShaderFormat() Q_DECL_NOTHROW
|
||||
: m_api(NoApi)
|
||||
, m_shaderType(Fragment)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW
|
|||
if (m_version < other.m_version)
|
||||
return false;
|
||||
|
||||
if (m_shaderType != other.m_shaderType)
|
||||
return false;
|
||||
|
||||
const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(),
|
||||
m_extensions.constEnd(),
|
||||
other.m_extensions.constBegin(),
|
||||
|
|
@ -119,12 +123,23 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW
|
|||
return true;
|
||||
}
|
||||
|
||||
QShaderFormat::ShaderType QShaderFormat::shaderType() const Q_DECL_NOTHROW
|
||||
{
|
||||
return m_shaderType;
|
||||
}
|
||||
|
||||
void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) Q_DECL_NOTHROW
|
||||
{
|
||||
m_shaderType = shaderType;
|
||||
}
|
||||
|
||||
bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.api() == rhs.api()
|
||||
&& lhs.version() == rhs.version()
|
||||
&& lhs.extensions() == rhs.extensions()
|
||||
&& lhs.vendor() == rhs.vendor();
|
||||
&& lhs.vendor() == rhs.vendor()
|
||||
&& lhs.shaderType() == rhs.shaderType();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -69,6 +69,15 @@ public:
|
|||
OpenGLES
|
||||
};
|
||||
|
||||
enum ShaderType : int {
|
||||
Vertex = 0,
|
||||
TessellationControl,
|
||||
TessellationEvaluation,
|
||||
Geometry,
|
||||
Fragment,
|
||||
Compute
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT QShaderFormat() Q_DECL_NOTHROW;
|
||||
|
||||
Q_GUI_EXPORT Api api() const Q_DECL_NOTHROW;
|
||||
|
|
@ -86,11 +95,15 @@ public:
|
|||
Q_GUI_EXPORT bool isValid() const Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT bool supports(const QShaderFormat &other) const Q_DECL_NOTHROW;
|
||||
|
||||
Q_GUI_EXPORT ShaderType shaderType() const Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT void setShaderType(ShaderType shaderType) Q_DECL_NOTHROW;
|
||||
|
||||
private:
|
||||
Api m_api;
|
||||
QVersionNumber m_version;
|
||||
QStringList m_extensions;
|
||||
QString m_vendor;
|
||||
ShaderType m_shaderType;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ namespace
|
|||
case QShaderLanguage::Const:
|
||||
return "const";
|
||||
case QShaderLanguage::Input:
|
||||
return "varying";
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -251,6 +251,17 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
|
|||
break;
|
||||
}
|
||||
|
||||
// We default out to a Fragment ShaderType if nothing is specified
|
||||
// as that was the initial behavior we introduced
|
||||
const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString();
|
||||
format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment
|
||||
: shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex
|
||||
: shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl
|
||||
: shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation
|
||||
: shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry
|
||||
: shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute
|
||||
: QShaderFormat::Fragment);
|
||||
|
||||
const QByteArray substitution = substitutionValue.toString().toUtf8();
|
||||
|
||||
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
|
||||
|
|
|
|||
|
|
@ -35,11 +35,13 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion)
|
||||
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion,
|
||||
QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment)
|
||||
{
|
||||
auto format = QShaderFormat();
|
||||
format.setApi(api);
|
||||
format.setVersion(QVersionNumber(majorVersion, minorVersion));
|
||||
format.setShaderType(shaderType);
|
||||
return format;
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +76,7 @@ namespace
|
|||
return edge;
|
||||
}
|
||||
|
||||
QShaderGraph createGraph()
|
||||
QShaderGraph createFragmentShaderGraph()
|
||||
{
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
|
|
@ -213,7 +215,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
|
|||
QTest::addColumn<QShaderFormat>("format");
|
||||
QTest::addColumn<QByteArray>("expectedCode");
|
||||
|
||||
const auto graph = createGraph();
|
||||
const auto graph = createFragmentShaderGraph();
|
||||
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
|
|
@ -580,120 +582,195 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
|
|||
QTest::addColumn<QShaderFormat>("format");
|
||||
QTest::addColumn<QByteArray>("expectedCode");
|
||||
|
||||
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0);
|
||||
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0);
|
||||
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
|
||||
{
|
||||
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0);
|
||||
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0);
|
||||
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
|
||||
|
||||
const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>();
|
||||
const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>();
|
||||
const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>();
|
||||
const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>();
|
||||
|
||||
for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) {
|
||||
const auto qualifierName = qualifierEnum.key(qualifierIndex);
|
||||
const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex));
|
||||
for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) {
|
||||
const auto qualifierName = qualifierEnum.key(qualifierIndex);
|
||||
const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex));
|
||||
|
||||
for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) {
|
||||
const auto typeName = typeEnum.key(typeIndex);
|
||||
const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex));
|
||||
for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) {
|
||||
const auto typeName = typeEnum.key(typeIndex);
|
||||
const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex));
|
||||
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
auto worldPosition = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
worldPosition.setParameter("name", "worldPosition");
|
||||
worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue));
|
||||
worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue));
|
||||
worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;",
|
||||
QByteArrayList() << "$qualifier highp $type $name;"));
|
||||
worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
|
||||
graph.addNode(worldPosition);
|
||||
graph.addNode(fragColor);
|
||||
|
||||
graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor"));
|
||||
|
||||
const auto gl2Code = (QByteArrayList() << "#version 110"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto gl3Code = (QByteArrayList() << "#version 130"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto gl4Code = (QByteArrayList() << "#version 400 core"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "out vec4 fragColor;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto es2Code = (QByteArrayList() << "#version 100"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto es3Code = (QByteArrayList() << "#version 300 es"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
|
||||
QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code;
|
||||
QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code;
|
||||
QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code;
|
||||
QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code;
|
||||
QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0, QShaderFormat::Vertex);
|
||||
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0, QShaderFormat::Vertex);
|
||||
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0, QShaderFormat::Vertex);
|
||||
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, QShaderFormat::Vertex);
|
||||
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0, QShaderFormat::Vertex);
|
||||
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
auto worldPosition = createNode({
|
||||
auto vertexPosition = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
worldPosition.setParameter("name", "worldPosition");
|
||||
worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue));
|
||||
worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue));
|
||||
worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;",
|
||||
vertexPosition.setParameter("name", "vertexPosition");
|
||||
vertexPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Input));
|
||||
vertexPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec4));
|
||||
|
||||
vertexPosition.addRule(es2, QShaderNode::Rule("",
|
||||
QByteArrayList() << "$qualifier highp $type $name;"));
|
||||
worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;",
|
||||
vertexPosition.addRule(gl2, QShaderNode::Rule("",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;",
|
||||
vertexPosition.addRule(gl3, QShaderNode::Rule("",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
|
||||
graph.addNode(worldPosition);
|
||||
graph.addNode(fragColor);
|
||||
|
||||
graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor"));
|
||||
graph.addNode(vertexPosition);
|
||||
|
||||
const auto gl2Code = (QByteArrayList() << "#version 110"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "attribute vec4 vertexPosition;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto gl3Code = (QByteArrayList() << "#version 130"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "out vec4 fragColor;"
|
||||
<< "in vec4 vertexPosition;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto gl4Code = (QByteArrayList() << "#version 400 core"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "out vec4 fragColor;"
|
||||
<< "in vec4 vertexPosition;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto es2Code = (QByteArrayList() << "#version 100"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "attribute highp vec4 vertexPosition;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
const auto es3Code = (QByteArrayList() << "#version 300 es"
|
||||
<< ""
|
||||
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3))
|
||||
.arg(toGlsl(typeValue))
|
||||
.toUtf8()
|
||||
<< "in highp vec4 vertexPosition;"
|
||||
<< ""
|
||||
<< "void main()"
|
||||
<< "{"
|
||||
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
|
||||
<< " gl_fragColor = v0;"
|
||||
<< "}"
|
||||
<< "").join("\n");
|
||||
|
||||
QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code;
|
||||
QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code;
|
||||
QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code;
|
||||
QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code;
|
||||
QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code;
|
||||
}
|
||||
QTest::addRow("Attribute header substitution ES2") << graph << es2 << es2Code;
|
||||
QTest::addRow("Attribute header substitution ES3") << graph << es3 << es3Code;
|
||||
QTest::addRow("Attribute header substitution GL2") << graph << gl2 << gl2Code;
|
||||
QTest::addRow("Attribute header substitution GL3") << graph << gl3 << gl3Code;
|
||||
QTest::addRow("Attribute header substitution GL4") << graph << gl4 << gl4Code;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue