QmlDesigner: Compile effect maker shaders using qsb tool

Task-number: QDS-10811
Change-Id: I6028dea262b2658838b59156ac062657cc4ef3f0
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Amr Essam
2023-10-11 18:59:03 +03:00
committed by Amr Elsayed
parent c5e4010842
commit d8bbbd2494
4 changed files with 83 additions and 35 deletions

View File

@@ -18,7 +18,7 @@ Column {
property var effectMakerModel: EffectMakerBackend.effectMakerModel property var effectMakerModel: EffectMakerBackend.effectMakerModel
property alias source: source property alias source: source
// The delay in ms to wait until updating the effect // The delay in ms to wait until updating the effect
readonly property int updateDelay: 200 readonly property int updateDelay: 100
// Create a dummy parent to host the effect qml object // Create a dummy parent to host the effect qml object
function createNewComponent() { function createNewComponent() {
@@ -183,16 +183,16 @@ Column {
target: effectMakerModel target: effectMakerModel
function onShadersBaked() { function onShadersBaked() {
console.log("Shaders Baked!") console.log("Shaders Baked!")
//updateTimer.restart(); // Disable for now updateTimer.restart()
} }
} }
Timer { Timer {
id: updateTimer id: updateTimer
interval: updateDelay; interval: updateDelay
onTriggered: { onTriggered: {
effectMakerModel.updateQmlComponent(); effectMakerModel.updateQmlComponent()
createNewComponent(); createNewComponent()
} }
} }
} }

View File

@@ -3,7 +3,7 @@ find_package(Qt6 OPTIONAL_COMPONENTS Gui Quick ShaderTools)
add_qtc_plugin(EffectMakerNew add_qtc_plugin(EffectMakerNew
CONDITION TARGET QmlDesigner AND TARGET Qt::ShaderTools CONDITION TARGET QmlDesigner AND TARGET Qt::ShaderTools
PLUGIN_DEPENDS PLUGIN_DEPENDS
QtCreator::Core QtCreator::QmlDesigner QtCreator::ProjectExplorer QtCreator::Core QtCreator::QmlDesigner QtCreator::ProjectExplorer QtCreator::QmlProjectManager
DEPENDS DEPENDS
Qt::Core Qt::Core
QtCreator::Utils Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick Qt::ShaderTools Qt::ShaderToolsPrivate QtCreator::Utils Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick Qt::ShaderTools Qt::ShaderToolsPrivate

View File

@@ -7,8 +7,7 @@
#include "syntaxhighlighterdata.h" #include "syntaxhighlighterdata.h"
#include "uniform.h" #include "uniform.h"
#include <QByteArrayView> #include <qmlprojectmanager/qmlproject.h>
#include <QVector2D>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
@@ -17,6 +16,10 @@
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/process.h>
#include <QByteArrayView>
#include <QVector2D>
namespace EffectMaker { namespace EffectMaker {
@@ -49,8 +52,14 @@ EffectMakerModel::EffectMakerModel(QObject *parent)
m_vertexShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.vert.qsb"); m_vertexShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.vert.qsb");
m_fragmentShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.frag.qsb"); m_fragmentShaderFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.frag.qsb");
if (!m_vertexSourceFile.open() || !m_fragmentSourceFile.open() if (!m_vertexSourceFile.open() || !m_fragmentSourceFile.open()
|| !m_vertexShaderFile.open() || !m_fragmentShaderFile.open()) || !m_vertexShaderFile.open() || !m_fragmentShaderFile.open()) {
qWarning() << "Unable to open temporary files"; qWarning() << "Unable to open temporary files";
} else {
m_vertexSourceFilename = m_vertexSourceFile.fileName();
m_fragmentSourceFilename = m_fragmentSourceFile.fileName();
m_vertexShaderFilename = m_vertexShaderFile.fileName();
m_fragmentShaderFilename = m_fragmentShaderFile.fileName();
}
} }
QHash<int, QByteArray> EffectMakerModel::roleNames() const QHash<int, QByteArray> EffectMakerModel::roleNames() const
@@ -720,6 +729,24 @@ QString EffectMakerModel::generateFragmentShader(bool includeUniforms)
return s; return s;
} }
void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader)
{
--m_remainingQsbTargets;
const QString errStr = qsbProcess->errorString();
if (!errStr.isEmpty())
qWarning() << QString("Failed to generate QSB file for: %1 %2").arg(shader, errStr);
if (m_remainingQsbTargets <= 0) {
Q_EMIT shadersBaked();
setShadersUpToDate(true);
// TODO: Mark shaders as baked, required by export later
}
qsbProcess->deleteLater();
}
// Generates string of the custom properties (uniforms) into ShaderEffect component // Generates string of the custom properties (uniforms) into ShaderEffect component
// Also generates QML images elements for samplers. // Also generates QML images elements for samplers.
void EffectMakerModel::updateCustomUniforms() void EffectMakerModel::updateCustomUniforms()
@@ -790,6 +817,14 @@ void EffectMakerModel::updateCustomUniforms()
void EffectMakerModel::bakeShaders() void EffectMakerModel::bakeShaders()
{ {
const QString failMessage = "Shader baking failed: ";
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (!target) {
qWarning() << failMessage << "Target not found";
return;
}
resetEffectError(ErrorPreprocessor); resetEffectError(ErrorPreprocessor);
if (m_vertexShader == generateVertexShader() && m_fragmentShader == generateFragmentShader()) { if (m_vertexShader == generateVertexShader() && m_fragmentShader == generateFragmentShader()) {
setShadersUpToDate(true); setShadersUpToDate(true);
@@ -813,12 +848,34 @@ void EffectMakerModel::bakeShaders()
QString fs = m_fragmentShader; QString fs = m_fragmentShader;
writeToFile(fs.toUtf8(), m_fragmentSourceFile.fileName(), FileType::Text); writeToFile(fs.toUtf8(), m_fragmentSourceFile.fileName(), FileType::Text);
//TODO: Compile shaders using external qsb tools QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit());
if (!qtVer) {
qWarning() << failMessage << "Qt version not found";
return;
}
Q_EMIT shadersBaked(); Utils::FilePath qsbPath = qtVer->binPath().pathAppended("qsb").withExecutableSuffix();
setShadersUpToDate(true); if (!qsbPath.exists()) {
qWarning() << failMessage << "QSB tool not found";
return;
}
// TODO: Mark shaders as baked, required by export later m_remainingQsbTargets = 2; // We only have 2 shaders
const QStringList srcPaths = {m_vertexSourceFilename, m_fragmentSourceFilename};
const QStringList outPaths = {m_vertexShaderFilename, m_fragmentShaderFilename};
for (int i = 0; i < 2; ++i) {
const auto workDir = Utils::FilePath::fromString(outPaths[i]);
QStringList args = {"-s", "--glsl", "\"300 es,120,150,440\"", "--hlsl", "50", "--msl", "12"};
args << "-o" << outPaths[i] << srcPaths[i];
auto qsbProcess = new Utils::Process(this);
connect(qsbProcess, &Utils::Process::done, this, [=] {
handleQsbProcessExit(qsbProcess, srcPaths[i]);
});
qsbProcess->setWorkingDirectory(workDir.absolutePath());
qsbProcess->setCommand({qsbPath, args});
qsbProcess->start();
}
} }
bool EffectMakerModel::shadersUpToDate() const bool EffectMakerModel::shadersUpToDate() const
@@ -857,8 +914,6 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
}; };
QString customImagesString = getQmlImagesString(localFiles); QString customImagesString = getQmlImagesString(localFiles);
QString vertexShaderFilename = "file:///" + m_fragmentShaderFile.fileName();
QString fragmentShaderFilename = "file:///" + m_vertexShaderFile.fileName();
QString s; QString s;
QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral(""); QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral("");
QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" "); QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" ");
@@ -896,8 +951,8 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
s += '\n' + customImagesString; s += '\n' + customImagesString;
s += '\n'; s += '\n';
s += l2 + "vertexShader: '" + vertexShaderFilename + "'\n"; s += l2 + "vertexShader: 'file://" + m_vertexShaderFilename + "'\n";
s += l2 + "fragmentShader: '" + fragmentShaderFilename + "'\n"; s += l2 + "fragmentShader: 'file://" + m_fragmentShaderFilename + "'\n";
s += l2 + "anchors.fill: parent\n"; s += l2 + "anchors.fill: parent\n";
if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) { if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) {
QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth()).arg(m_shaderFeatures.gridMeshHeight()); QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth()).arg(m_shaderFeatures.gridMeshHeight());
@@ -909,21 +964,6 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
return s; return s;
} }
Utils::FilePath EffectMakerModel::qsbPath() const
{
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (target) {
if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit())) {
Utils::FilePath path = qtVer->binPath().pathAppended("qsb").withExecutableSuffix();
if (path.exists())
return path;
}
}
qWarning() << "Shader baking failed, QSB not found.";
return {};
}
void EffectMakerModel::updateQmlComponent() void EffectMakerModel::updateQmlComponent()
{ {
// Clear possible QML runtime errors // Clear possible QML runtime errors

View File

@@ -12,6 +12,10 @@
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QTemporaryFile> #include <QTemporaryFile>
namespace ProjectExplorer {
class Target;
}
namespace Utils { namespace Utils {
class Process; class Process;
} }
@@ -127,8 +131,7 @@ private:
QString getCustomShaderVaryings(bool outState); QString getCustomShaderVaryings(bool outState);
QString generateVertexShader(bool includeUniforms = true); QString generateVertexShader(bool includeUniforms = true);
QString generateFragmentShader(bool includeUniforms = true); QString generateFragmentShader(bool includeUniforms = true);
void handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader);
Utils::FilePath qsbPath() const;
void updateCustomUniforms(); void updateCustomUniforms();
void bakeShaders(); void bakeShaders();
@@ -142,6 +145,7 @@ private:
bool m_isEmpty = true; bool m_isEmpty = true;
// True when shaders haven't changed since last baking // True when shaders haven't changed since last baking
bool m_shadersUpToDate = true; bool m_shadersUpToDate = true;
int m_remainingQsbTargets = 0;
QMap<int, EffectError> m_effectErrors; QMap<int, EffectError> m_effectErrors;
ShaderFeatures m_shaderFeatures; ShaderFeatures m_shaderFeatures;
QStringList m_shaderVaryingVariables; QStringList m_shaderVaryingVariables;
@@ -154,6 +158,10 @@ private:
QTemporaryFile m_vertexSourceFile; QTemporaryFile m_vertexSourceFile;
QTemporaryFile m_fragmentShaderFile; QTemporaryFile m_fragmentShaderFile;
QTemporaryFile m_vertexShaderFile; QTemporaryFile m_vertexShaderFile;
QString m_fragmentSourceFilename;
QString m_vertexSourceFilename;
QString m_fragmentShaderFilename;
QString m_vertexShaderFilename;
// Used in exported QML, at root of the file // Used in exported QML, at root of the file
QString m_exportedRootPropertiesString; QString m_exportedRootPropertiesString;
// Used in exported QML, at ShaderEffect component of the file // Used in exported QML, at ShaderEffect component of the file