From cec9e6493e6f7c82c7c5ba5b3c5e8c3f22173fba Mon Sep 17 00:00:00 2001 From: Amr Essam Date: Fri, 1 Sep 2023 10:59:02 +0300 Subject: [PATCH] QmlDesigner: Add Effect Maker shader error propagation In case of manual edit of shaders, this simple system detects common errors that might be found in a shader. Task-number: QDS-10499 Change-Id: I0c70ac85ef519880dcd98642c5927f037f113f94 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../effectmaker/effectmakermodel.cpp | 75 +++++++++++++++++++ .../components/effectmaker/effectmakermodel.h | 19 +++++ 2 files changed, 94 insertions(+) diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp index 228154fc6a4..b122a4e8530 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp @@ -6,6 +6,8 @@ #include "compositionnode.h" #include "uniform.h" +#include + #include namespace QmlDesigner { @@ -152,4 +154,77 @@ const QString EffectMakerModel::getFSUniforms() return s; } + +// Detects common GLSL error messages and returns potential +// additional error information related to them. +QString EffectMakerModel::detectErrorMessage(const QString &errorMessage) +{ + static QHash nodeErrors { + { "'BLUR_HELPER_MAX_LEVEL' : undeclared identifier", "BlurHelper"}, + { "'iSourceBlur1' : undeclared identifier", "BlurHelper"}, + { "'hash23' : no matching overloaded function found", "NoiseHelper" }, + { "'HASH_BOX_SIZE' : undeclared identifier", "NoiseHelper" }, + { "'pseudo3dNoise' : no matching overloaded function found", "NoiseHelper" } + }; + + QString missingNodeError = QStringLiteral("Are you missing a %1 node?\n"); + QHash::const_iterator i = nodeErrors.constBegin(); + while (i != nodeErrors.constEnd()) { + if (errorMessage.contains(i.key())) + return missingNodeError.arg(i.value()); + ++i; + } + return QString(); +} + +// Return first error message (if any) +EffectError EffectMakerModel::effectError() const +{ + for (const EffectError &e : std::as_const(m_effectErrors)) { + if (!e.m_message.isEmpty()) + return e; + } + return {}; +} + +// Set the effect error message with optional type and lineNumber. +// Type comes from ErrorTypes, defaulting to common errors (-1). +// Note that type must match with UI editor tab index. +void EffectMakerModel::setEffectError(const QString &errorMessage, int type, int lineNumber) +{ + EffectError error; + error.m_type = type; + if (type == 1 || type == 2) { + // For shaders, get the line number from baker output. + // Which is something like "ERROR: :15: message" + int glslErrorLineNumber = -1; + static QRegularExpression spaceReg("\\s+"); + QStringList errorStringList = errorMessage.split(spaceReg, Qt::SkipEmptyParts); + if (errorStringList.size() >= 2) { + QString lineString = errorStringList.at(1).trimmed(); + if (lineString.size() >= 3) { + // String is ":[linenumber]:", get only the number. + glslErrorLineNumber = lineString.sliced(1, lineString.size() - 2).toInt(); + } + } + error.m_line = glslErrorLineNumber; + } else { + // For QML (and others) use given linenumber + error.m_line = lineNumber; + } + + QString additionalErrorInfo = detectErrorMessage(errorMessage); + error.m_message = additionalErrorInfo + errorMessage; + m_effectErrors.insert(type, error); + Q_EMIT effectErrorChanged(); +} + +void EffectMakerModel::resetEffectError(int type) +{ + if (m_effectErrors.contains(type)) { + m_effectErrors.remove(type); + Q_EMIT effectErrorChanged(); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h index de26b2f38f3..741647a1425 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h @@ -13,6 +13,17 @@ namespace QmlDesigner { class CompositionNode; class Uniform; +struct EffectError { + Q_GADGET + Q_PROPERTY(QString message MEMBER m_message) + Q_PROPERTY(int line MEMBER m_line) + Q_PROPERTY(int type MEMBER m_type) +public: + QString m_message; + int m_line = -1; + int m_type = -1; +}; + class EffectMakerModel : public QAbstractListModel { Q_OBJECT @@ -36,6 +47,7 @@ public: signals: void isEmptyChanged(); void selectedIndexChanged(int idx); + void effectErrorChanged(); private: enum Roles { @@ -51,11 +63,18 @@ private: const QString getVSUniforms(); const QString getFSUniforms(); + QString detectErrorMessage(const QString &errorMessage); + EffectError effectError() const; + void setEffectError(const QString &errorMessage, int type, int lineNumber); + void resetEffectError(int type); + QList m_nodes; int m_selectedIndex = -1; bool m_isEmpty = true; + QMap m_effectErrors; + ShaderFeatures m_shaderFeatures; };