summaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2022-10-11 10:03:02 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2022-10-11 13:31:35 +0200
commita3cb68f16d35ff1d750257a0fcd443a4c88ce572 (patch)
tree30df11c906f909bc96050c4079120dcba190ef82 /src/imports
parent153b7990dc473f7d1dbe24d5d760ddfe5e9538ed (diff)
Qt Graphical Effects: Cache shaders between runs
In order to support multiple graphics backends, we generate qsb files in the Qt 6 version of Qt Graphical Effects. For a few effects, like anything depending on Gaussian Blur, this is done at runtime. Generating these is expensive, and we were generating them once per created item in the scene. Since the shaders will often be identical, there is no need to do this. Instead, we cache them and reuse identical shaders, even across runs. As a failsafe, the environment variable QT_GFXSHADERBUILDER_REFRESH_CACHE will force the cache to be updated. Pick-to: 6.4 Fixes: QTBUG-107468 Change-Id: I94cab6cc6f528a4071833e3d66b50606e3200d97 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/graphicaleffects5/private/qgfxshaderbuilder.cpp101
-rw-r--r--src/imports/graphicaleffects5/private/qgfxshaderbuilder_p.h5
2 files changed, 53 insertions, 53 deletions
diff --git a/src/imports/graphicaleffects5/private/qgfxshaderbuilder.cpp b/src/imports/graphicaleffects5/private/qgfxshaderbuilder.cpp
index ed5e2be..756ed83 100644
--- a/src/imports/graphicaleffects5/private/qgfxshaderbuilder.cpp
+++ b/src/imports/graphicaleffects5/private/qgfxshaderbuilder.cpp
@@ -6,8 +6,10 @@
#include <QtCore/QDebug>
#include <QtCore/QUrl>
-#include <QtCore/QTemporaryFile>
#include <QtCore/QVarLengthArray>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QCryptographicHash>
+#include <QtCore/QDir>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
@@ -46,34 +48,22 @@ QT_BEGIN_NAMESPACE
QGfxShaderBuilder::QGfxShaderBuilder()
{
- QList<QShaderBaker::GeneratedShader> targets;
-
- QSGRendererInterface::GraphicsApi graphicsApi = QQuickWindow::graphicsApi();
- switch (graphicsApi) {
- case QSGRendererInterface::Direct3D11:
- targets.append({ QShader::HlslShader, QShaderVersion(50) });
- break;
- case QSGRendererInterface::OpenGL:
- targets.append({ QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs) });
- targets.append({ QShader::GlslShader, QShaderVersion(120) });
- targets.append({ QShader::GlslShader, QShaderVersion(150) });
- break;
- case QSGRendererInterface::Metal:
- targets.append({ QShader::MslShader, QShaderVersion(12) });
- break;
- case QSGRendererInterface::Vulkan:
- targets.append({ QShader::SpirvShader, QShaderVersion(100) });
- break;
- default:
- qWarning("QGfxShaderBuilder: Unsupported graphics backend. No shaders will be generated.");
- break;
- }
+ QList<QShaderBaker::GeneratedShader> targets =
+ {
+ { QShader::HlslShader, QShaderVersion(50) },
+ { QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs) },
+ { QShader::GlslShader, QShaderVersion(120) },
+ { QShader::GlslShader, QShaderVersion(150) },
+ { QShader::MslShader, QShaderVersion(12) },
+ { QShader::SpirvShader, QShaderVersion(100) }
+ };
m_shaderBaker.setGeneratedShaders(targets);
m_shaderBaker.setGeneratedShaderVariants({ QShader::StandardShader,
QShader::BatchableVertexShader });
#ifndef QT_NO_OPENGL
+ QSGRendererInterface::GraphicsApi graphicsApi = QQuickWindow::graphicsApi();
if (graphicsApi == QSGRendererInterface::OpenGL) {
// The following code makes the assumption that an OpenGL context the GUI
// thread will get the same capabilities as the render thread's OpenGL
@@ -443,45 +433,58 @@ QVariantMap QGfxShaderBuilder::gaussianBlur(const QJSValue &parameters)
QUrl QGfxShaderBuilder::buildFragmentShader(const QByteArray &code)
{
- delete m_fragmentShader;
- m_fragmentShader = new QTemporaryFile(this);
-
- return buildShader(code, QShader::FragmentStage, m_fragmentShader);
+ return buildShader(code, QShader::FragmentStage);
}
QUrl QGfxShaderBuilder::buildVertexShader(const QByteArray &code)
{
- delete m_vertexShader;
- m_vertexShader = new QTemporaryFile(this);
-
- return buildShader(code, QShader::VertexStage, m_vertexShader);
+ return buildShader(code, QShader::VertexStage);
}
QUrl QGfxShaderBuilder::buildShader(const QByteArray &code,
- QShader::Stage stage,
- QTemporaryFile *output)
+ QShader::Stage stage)
{
- if (!output->open()) {
- qWarning() << "QGfxShaderBuilder: Failed to create temporary files";
- return QUrl{};
- }
+ static bool recreateShaders = qEnvironmentVariableIntValue("QT_GFXSHADERBUILDER_REFRESH_CACHE");
+
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(code);
+
+ QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ + QStringLiteral("/_qt_QGfxShaderBuilder_")
+ + QStringLiteral(QT_VERSION_STR)
+ + QStringLiteral("/");
+ QString filePath = path
+ + fileNameHash.result().toHex()
+ + QStringLiteral(".qsb");
+
+ if (!QFile::exists(filePath) || recreateShaders) {
+ if (!QDir().mkpath(path)) {
+ qWarning() << "QGfxShaderBuilder: Failed to create path:" << path;
+ return QUrl{};
- m_shaderBaker.setSourceString(code, stage, output->fileName());
- {
- QShader compiledShader = m_shaderBaker.bake();
- if (!compiledShader.isValid()) {
- qWarning() << "QGfxShaderBuilder: Failed to compile shader for stage "
- << stage << ": "
- << m_shaderBaker.errorMessage()
- << QString(code).replace('\n', QChar(QChar::LineFeed));
+ }
+
+ QFile output(filePath);
+ if (!output.open(QIODevice::WriteOnly)) {
+ qWarning() << "QGfxShaderBuilder: Failed to store shader cache in file:" << filePath;
return QUrl{};
}
- output->write(compiledShader.serialized());
- }
- output->close();
+ m_shaderBaker.setSourceString(code, stage, filePath);
+ {
+ QShader compiledShader = m_shaderBaker.bake();
+ if (!compiledShader.isValid()) {
+ qWarning() << "QGfxShaderBuilder: Failed to compile shader for stage "
+ << stage << ": "
+ << m_shaderBaker.errorMessage()
+ << QString(code).replace('\n', QChar(QChar::LineFeed));
+ return QUrl{};
+ }
+ output.write(compiledShader.serialized());
+ }
+ }
- return QUrl::fromLocalFile(output->fileName());
+ return QUrl::fromLocalFile(filePath);
}
QT_END_NAMESPACE
diff --git a/src/imports/graphicaleffects5/private/qgfxshaderbuilder_p.h b/src/imports/graphicaleffects5/private/qgfxshaderbuilder_p.h
index 5decd70..2dc0fca 100644
--- a/src/imports/graphicaleffects5/private/qgfxshaderbuilder_p.h
+++ b/src/imports/graphicaleffects5/private/qgfxshaderbuilder_p.h
@@ -27,13 +27,10 @@ public:
Q_INVOKABLE QUrl buildFragmentShader(const QByteArray &code);
private:
- QUrl buildShader(const QByteArray &code, QShader::Stage stage, QTemporaryFile *output);
+ QUrl buildShader(const QByteArray &code, QShader::Stage stage);
int m_maxBlurSamples = 0;
QShaderBaker m_shaderBaker;
-
- QTemporaryFile *m_fragmentShader = nullptr;
- QTemporaryFile *m_vertexShader = nullptr;
};
QT_END_NAMESPACE