From 02abf29fa5770f201a6d735b318f79c33edb3320 Mon Sep 17 00:00:00 2001 From: Amr Essam Date: Mon, 25 Sep 2023 10:44:31 +0300 Subject: [PATCH] QmlDesigner: Complete shaders baking for effect maker Also add versioning support Task-number: QDS-10499 Change-Id: If75222e3569d361b0d7bece70867e4020132c1bd Reviewed-by: Miikka Heikkinen Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../effectmakernew/effectmakermodel.cpp | 82 ++++++++++++++++++- src/plugins/effectmakernew/effectmakermodel.h | 5 ++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 438fb8e4201..8b1836a5afa 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -14,9 +14,41 @@ namespace EffectMaker { +enum class FileType +{ + Binary, + Text +}; + +static bool writeToFile(const QByteArray &buf, const QString &filename, FileType fileType) +{ + QDir().mkpath(QFileInfo(filename).path()); + QFile f(filename); + QIODevice::OpenMode flags = QIODevice::WriteOnly | QIODevice::Truncate; + if (fileType == FileType::Text) + flags |= QIODevice::Text; + if (!f.open(flags)) { + qWarning() << "Failed to open file for writing:" << filename; + return false; + } + f.write(buf); + return true; +} + EffectMakerModel::EffectMakerModel(QObject *parent) : QAbstractListModel{parent} { + m_vertexShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.vert.qsb"); + m_fragmentShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.frag.qsb"); + // TODO: Will be revisted later when saving output files + if (m_vertexShaderFile.open()) + qInfo() << "Using temporary vs file:" << m_vertexShaderFile.fileName(); + if (m_fragmentShaderFile.open()) + qInfo() << "Using temporary fs file:" << m_fragmentShaderFile.fileName(); + + // Prepare baker + m_baker.setGeneratedShaderVariants({ QShader::StandardShader }); + updateBakedShaderVersions(); } QHash EffectMakerModel::roleNames() const @@ -97,6 +129,21 @@ void EffectMakerModel::removeNode(int idx) setIsEmpty(true); } +void EffectMakerModel::updateBakedShaderVersions() +{ + QList targets; + targets.append({ QShader::SpirvShader, QShaderVersion(100) }); // Vulkan 1.0 + targets.append({ QShader::HlslShader, QShaderVersion(50) }); // Shader Model 5.0 + targets.append({ QShader::MslShader, QShaderVersion(12) }); // Metal 1.2 + targets.append({ QShader::GlslShader, QShaderVersion(300, QShaderVersion::GlslEs) }); // GLES 3.0+ + targets.append({ QShader::GlslShader, QShaderVersion(410) }); // OpenGL 4.1+ + targets.append({ QShader::GlslShader, QShaderVersion(330) }); // OpenGL 3.3 + targets.append({ QShader::GlslShader, QShaderVersion(140) }); // OpenGL 3.1 + //TODO: Do we need support for legacy shaders 100, 120? + + m_baker.setGeneratedShaders(targets); +} + QString EffectMakerModel::fragmentShader() const { return m_fragmentShader; @@ -744,7 +791,40 @@ void EffectMakerModel::bakeShaders() updateCustomUniforms(); - // TODO: Shaders baking + setVertexShader(generateVertexShader()); + QString vs = m_vertexShader; + m_baker.setSourceString(vs.toUtf8(), QShader::VertexStage); + + QShader vertShader = m_baker.bake(); + if (!vertShader.isValid()) { + qWarning() << "Shader baking failed:" << qPrintable(m_baker.errorMessage()); + setEffectError(m_baker.errorMessage().split('\n').first(), ErrorVert); + } else { + QString filename = m_vertexShaderFile.fileName(); + writeToFile(vertShader.serialized(), filename, FileType::Binary); + resetEffectError(ErrorVert); + } + + setFragmentShader(generateFragmentShader()); + QString fs = m_fragmentShader; + m_baker.setSourceString(fs.toUtf8(), QShader::FragmentStage); + + QShader fragShader = m_baker.bake(); + if (!fragShader.isValid()) { + qWarning() << "Shader baking failed:" << qPrintable(m_baker.errorMessage()); + setEffectError(m_baker.errorMessage().split('\n').first(), ErrorFrag); + } else { + QString filename = m_fragmentShaderFile.fileName(); + writeToFile(fragShader.serialized(), filename, FileType::Binary); + resetEffectError(ErrorFrag); + } + + if (vertShader.isValid() && fragShader.isValid()) { + Q_EMIT shadersBaked(); + setShadersUpToDate(true); + } + + // TODO: Mark shaders as baked, required by export later } bool EffectMakerModel::shadersUpToDate() const diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 0dd858d5026..aa418df303e 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -65,6 +66,7 @@ signals: void selectedIndexChanged(int idx); void effectErrorChanged(); void shadersUpToDateChanged(); + void shadersBaked(); private: enum Roles { @@ -90,6 +92,7 @@ private: const QString getVSUniforms(); const QString getFSUniforms(); + void updateBakedShaderVersions(); QString detectErrorMessage(const QString &errorMessage); EffectError effectError() const; void setEffectError(const QString &errorMessage, int type = -1, int lineNumber = -1); @@ -128,6 +131,8 @@ private: QStringList m_defaultRootVertexShader; QStringList m_defaultRootFragmentShader; QShaderBaker m_baker; + QTemporaryFile m_fragmentShaderFile; + QTemporaryFile m_vertexShaderFile; // Used in exported QML, at root of the file QString m_exportedRootPropertiesString; // Used in exported QML, at ShaderEffect component of the file