summaryrefslogtreecommitdiffstats
path: root/src/api
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-09-03 17:36:07 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-09-12 06:43:23 +0300
commit82574e7d6317898600958c356053cfdaa7321c32 (patch)
treed4d099d426094292a01e81cbb3f389a20a961cfc /src/api
parent0d6360909793aab11c66f4b8f7001f71cbacfee7 (diff)
Implement shader caching
Currently loaded shaders can now cached with an API call in either source code or binary format. It is necessary to do it that way as the shader cache can only be created in the target hardware. Task-number: QT3DS-3914 Change-Id: I094e8624943904c311ada2259a84b8c183f792f5 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/api')
-rw-r--r--src/api/studio3d/q3dscommandqueue.cpp49
-rw-r--r--src/api/studio3d/q3dscommandqueue_p.h59
-rw-r--r--src/api/studio3d/q3dspresentation.cpp259
-rw-r--r--src/api/studio3d/q3dspresentation.h8
-rw-r--r--src/api/studio3d/q3dspresentation_p.h10
-rw-r--r--src/api/studio3d/q3dssurfaceviewer.cpp1
-rw-r--r--src/api/studio3dqml/q3dsrenderer.cpp26
-rw-r--r--src/api/studio3dqml/q3dsruntimeInitializerthread.cpp5
-rw-r--r--src/api/studio3dqml/q3dsruntimeInitializerthread_p.h3
-rw-r--r--src/api/studio3dqml/q3dsstudio3d.cpp25
10 files changed, 364 insertions, 81 deletions
diff --git a/src/api/studio3d/q3dscommandqueue.cpp b/src/api/studio3d/q3dscommandqueue.cpp
index 8ec07ee..06bd73f 100644
--- a/src/api/studio3d/q3dscommandqueue.cpp
+++ b/src/api/studio3d/q3dscommandqueue.cpp
@@ -46,27 +46,6 @@ QString ElementCommand::toString() const
}
CommandQueue::CommandQueue()
- : m_visibleChanged(false)
- , m_scaleModeChanged(false)
- , m_stereoModeChanged(false)
- , m_stereoEyeSeparationChanged(false)
- , m_shadeModeChanged(false)
- , m_showRenderStatsChanged(false)
- , m_matteColorChanged(false)
- , m_sourceChanged(false)
- , m_variantListChanged(false)
- , m_globalAnimationTimeChanged(false)
- , m_delayedLoadingChanged(false)
- , m_visible(false)
- , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter)
- , m_stereoMode(Q3DSViewerSettings::StereoModeMono)
- , m_stereoEyeSeparation(0.4)
- , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded)
- , m_showRenderStats(false)
- , m_matteColor(Qt::black)
- , m_delayedLoading(false)
- , m_matteEnabled(false)
- , m_size(0)
{
qRegisterMetaType<CommandType>();
}
@@ -212,6 +191,25 @@ ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandTy
return cmd;
}
+ElementCommand &CommandQueue::queueCommand(CommandType commandType)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(CommandType commandType, bool value)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_boolValue = value;
+
+ return cmd;
+}
+
void CommandQueue::copyCommands(CommandQueue &fromQueue)
{
m_visibleChanged = m_visibleChanged || fromQueue.m_visibleChanged;
@@ -228,6 +226,7 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
= m_globalAnimationTimeChanged || fromQueue.m_globalAnimationTimeChanged;
m_delayedLoadingChanged = m_delayedLoadingChanged || fromQueue.m_delayedLoadingChanged;
m_matteEnabledChanged = m_matteEnabledChanged || fromQueue.m_matteEnabledChanged;
+ m_shaderCacheFileChanged = m_shaderCacheFileChanged || fromQueue.m_shaderCacheFileChanged;
if (fromQueue.m_visibleChanged)
m_visible = fromQueue.m_visible;
@@ -253,6 +252,8 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
m_delayedLoading = fromQueue.m_delayedLoading;
if (fromQueue.m_matteEnabledChanged)
m_matteEnabled = fromQueue.m_matteEnabled;
+ if (fromQueue.m_shaderCacheFileChanged)
+ m_shaderCacheFile = fromQueue.m_shaderCacheFile;
// Pending queue may be synchronized multiple times between queue processing, so let's append
// to the existing queue rather than clearing it.
@@ -313,9 +314,12 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
case CommandType_RequestSlideInfo:
case CommandType_UnloadSlide:
case CommandType_PreloadSlide:
+ queueCommand(source.m_elementPath, source.m_commandType);
+ break;
case CommandType_RequestDataInputs:
case CommandType_RequestDataOutputs:
- queueCommand(source.m_elementPath, source.m_commandType);
+ case CommandType_RequestExportShaderCache:
+ queueCommand(source.m_commandType, source.m_boolValue);
break;
default:
queueCommand(QString(), CommandType_Invalid, false);
@@ -339,6 +343,7 @@ void CommandQueue::clear(bool deleteCommandData)
m_globalAnimationTimeChanged = false;
m_delayedLoadingChanged = false;
m_matteEnabledChanged = false;
+ m_shaderCacheFileChanged = false;
if (deleteCommandData) {
for (int i = 0; i < m_size; ++i) {
diff --git a/src/api/studio3d/q3dscommandqueue_p.h b/src/api/studio3d/q3dscommandqueue_p.h
index de1f2b1..2f98ed6 100644
--- a/src/api/studio3d/q3dscommandqueue_p.h
+++ b/src/api/studio3d/q3dscommandqueue_p.h
@@ -75,13 +75,14 @@ enum CommandType {
CommandType_DeleteMaterials,
CommandType_CreateMeshes,
CommandType_DeleteMeshes,
+ CommandType_PreloadSlide,
+ CommandType_UnloadSlide,
// Requests
CommandType_RequestSlideInfo,
CommandType_RequestDataInputs,
- CommandType_PreloadSlide,
- CommandType_UnloadSlide,
- CommandType_RequestDataOutputs
+ CommandType_RequestDataOutputs,
+ CommandType_RequestExportShaderCache
};
class Q_STUDIO3D_EXPORT ElementCommand
@@ -132,34 +133,38 @@ public:
ElementCommand &queueCommand(const QString &elementPath, CommandType commandType);
ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
void *commandData);
+ ElementCommand &queueCommand(CommandType commandType);
+ ElementCommand &queueCommand(CommandType commandType, bool value);
void copyCommands(CommandQueue &fromQueue);
- bool m_visibleChanged;
- bool m_scaleModeChanged;
- bool m_stereoModeChanged;
- bool m_stereoEyeSeparationChanged;
- bool m_shadeModeChanged;
- bool m_showRenderStatsChanged;
- bool m_matteColorChanged;
- bool m_sourceChanged;
- bool m_variantListChanged;
- bool m_globalAnimationTimeChanged;
- bool m_delayedLoadingChanged;
- bool m_matteEnabledChanged;
-
- bool m_visible;
- Q3DSViewerSettings::ScaleMode m_scaleMode;
- Q3DSViewerSettings::StereoMode m_stereoMode;
- double m_stereoEyeSeparation;
- Q3DSViewerSettings::ShadeMode m_shadeMode;
- bool m_showRenderStats;
- QColor m_matteColor;
+ bool m_visibleChanged = false;
+ bool m_scaleModeChanged = false;
+ bool m_stereoModeChanged = false;
+ bool m_stereoEyeSeparationChanged = false;
+ bool m_shadeModeChanged = false;
+ bool m_showRenderStatsChanged = false;
+ bool m_matteColorChanged = false;
+ bool m_sourceChanged = false;
+ bool m_variantListChanged = false;
+ bool m_globalAnimationTimeChanged = false;
+ bool m_delayedLoadingChanged = false;
+ bool m_matteEnabledChanged = false;
+ bool m_shaderCacheFileChanged = false;
+
+ bool m_visible = false;
+ Q3DSViewerSettings::ScaleMode m_scaleMode = Q3DSViewerSettings::ScaleModeCenter;
+ Q3DSViewerSettings::StereoMode m_stereoMode = Q3DSViewerSettings::StereoModeMono;
+ double m_stereoEyeSeparation = 0.4;
+ Q3DSViewerSettings::ShadeMode m_shadeMode = Q3DSViewerSettings::ShadeModeShaded;
+ bool m_showRenderStats = false;
+ QColor m_matteColor = QColor(Qt::black);
QUrl m_source;
QStringList m_variantList;
- qint64 m_globalAnimationTime;
- bool m_delayedLoading;
- bool m_matteEnabled;
+ qint64 m_globalAnimationTime = 0;
+ bool m_delayedLoading = false;
+ bool m_matteEnabled = false;
+ QUrl m_shaderCacheFile;
void clear(bool deleteCommandData);
int size() const { return m_size; }
@@ -170,7 +175,7 @@ private:
ElementCommand &nextFreeCommand();
CommandList m_elementCommands;
- int m_size;
+ int m_size = 0;
};
QT_END_NAMESPACE
diff --git a/src/api/studio3d/q3dspresentation.cpp b/src/api/studio3d/q3dspresentation.cpp
index beb0394..e782cfe 100644
--- a/src/api/studio3d/q3dspresentation.cpp
+++ b/src/api/studio3d/q3dspresentation.cpp
@@ -34,10 +34,15 @@
#include "q3dsdatainput_p.h"
#include "q3dsdataoutput_p.h"
#include "q3dsgeometry_p.h"
+#include "studioutils_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qsavefile.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
#include <QtGui/qevent.h>
QT_BEGIN_NAMESPACE
@@ -607,6 +612,161 @@ void Q3DSPresentation::unloadSlide(const QString &elementPath)
}
/*!
+ \qmlmethod Presentation::exportShaderCache(url shaderCacheFile, bool binaryShaders)
+
+ Writes the shaders currently in use to the file specified by \a shaderCacheFile URL.
+ If \a binaryShaders property is \c{true}, precompiled shaders are exported. Otherwise,
+ the shader source code is exported.
+
+ Exporting shader cache is an asynchronous operation.
+ The shaderCacheExported signal is emitted when the export is complete.
+
+ Exporting shader cache should be done at the point of application execution where all the
+ shaders that should be initialized at application startup have been initialized.
+
+ \note Exporting shader cache is only supported if no shaders have been originally loaded
+ from a shader cache. Specifying no shader cache file or an empty or invalid shader cache file
+ with shaderCacheFile property allows shader generation.
+
+ \sa shaderCacheFile, shaderCacheExported
+ */
+/*!
+ Writes the shaders currently in use to the file specified by \a shaderCacheFile URL.
+ If \a binaryShaders property is \c{true}, precompiled shaders are exported. Otherwise,
+ the shader source code is exported.
+
+ The shaderCacheExported signal is emitted when the export is complete.
+
+ Exporting shader cache should be done at the point of application execution where all the
+ shaders that should be initialized at application startup have been initialized.
+
+ \note Exporting shader cache is only supported if no shaders have been originally loaded
+ from a shader cache. Specifying no shader cache file or an empty or invalid shader cache file
+ with shaderCacheFile property allows shader generation.
+
+ \sa shaderCacheFile, shaderCacheExported
+ */
+void Q3DSPresentation::exportShaderCache(const QUrl &shaderCacheFile, bool binaryShaders)
+{
+ d_ptr->exportShaderCache(binaryShaders, false);
+ if (d_ptr->m_commandQueue)
+ d_ptr->m_shaderCacheWritePending = shaderCacheFile;
+ else
+ d_ptr->writeShaderCache(shaderCacheFile);
+}
+
+/*!
+ \qmlmethod Presentation::exportShaderCache(bool binaryShaders)
+
+ Exports the shaders currently in use and dumps the resulting cache encoded with base64 into
+ stderr. This function is provided as a means to extract the shader cache from environments
+ without a writable disk. The base64 output needs to be converted back to binary
+ representation to be usable as a shader cache file. The Qt 3D Studio Viewer provides
+ a command line parameter \c --convert-shader-cache to do this conversion.
+
+ If \a binaryShaders property is \c{true}, precompiled shaders are exported.
+ Otherwise, the shader source code is exported.
+
+ Exporting shader cache is an asynchronous operation.
+ The shaderCacheExported signal is emitted when the export is complete.
+
+ Exporting shader cache should be done at the point of application execution where all the
+ shaders that should be initialized at application startup have been initialized.
+
+ \note Exporting shader cache is only supported if no shaders have been originally loaded
+ from a shader cache. Specifying no shader cache file or an empty or invalid shader cache file
+ with shaderCacheFile property allows shader generation.
+
+ \sa shaderCacheFile, shaderCacheExported
+ */
+/*!
+ Exports the shaders currently in use and dumps the resulting cache encoded with base64 into
+ stderr. This function is provided as a means to extract the shader cache from environments
+ without a writable disk. The base64 output needs to be converted back to binary
+ representation to be usable as a shader cache file. The Qt 3D Studio Viewer provides
+ a command line parameter \c --convert-shader-cache to do this conversion.
+
+ If \a binaryShaders property is \c{true}, precompiled shaders are exported.
+ Otherwise, the shader source code is exported.
+
+ The shaderCacheExported signal is emitted when the export is complete.
+
+ Exporting shader cache should be done at the point of application execution where all the
+ shaders that should be initialized at application startup have been initialized.
+
+ \note Exporting shader cache is only supported if no shaders have been originally loaded
+ from a shader cache. Specifying no shader cache file or an empty or invalid shader cache file
+ with shaderCacheFile property allows shader generation.
+
+ \sa shaderCacheFile, shaderCacheExported
+ */
+void Q3DSPresentation::exportShaderCache(bool binaryShaders)
+{
+ d_ptr->exportShaderCache(binaryShaders, true);
+}
+
+/*!
+ \qmlproperty url Presentation::shaderCacheFile
+
+ Specifies the shader cache file to be used for initial shader initialization.
+ This property value must be set before the presentation is shown.
+ Using cached shaders improves presentation initialization speed.
+
+ If this property is not set, all shaders are generated normally.
+
+ If this property points to a valid shader cache file, new shader cache generation is not
+ supported.
+
+ The default value is an empty url.
+
+ \sa exportShaderCache(), shaderCacheExport
+ */
+/*!
+ Specifies the shader cache file to be used for initial shader initialization.
+ This property value must be set before the presentation is shown.
+ Using cached shaders improves presentation initialization speed.
+
+ If this property is not set, all shaders are generated normally.
+
+ If this property points to a valid shader cache file, new shader cache generation is not
+ supported.
+
+ The default value is an empty url.
+
+ \sa exportShaderCache(), shaderCacheExport
+ */
+QUrl Q3DSPresentation::shaderCacheFile() const
+{
+ return d_ptr->m_shaderCacheFile;
+}
+
+void Q3DSPresentation::setShaderCacheFile(const QUrl &fileName)
+{
+ if (d_ptr->m_shaderCacheFile != fileName) {
+ d_ptr->setShaderCacheFile(fileName);
+ Q_EMIT shaderCacheFileChanged(fileName);
+ }
+}
+
+/*!
+ \qmlsignal Presentation::shaderCacheExported(bool success)
+
+ Emitted when a shader cache export is completed. The parameter \a success indicates whether
+ or not the export was successful.
+
+ \sa shaderCacheExport(), shaderCacheFile
+ */
+
+/*!
+ \fn Q3DSPresentation::shaderCacheExported(bool success)
+
+ Emitted when a shader cache export is completed. The parameter \a success indicates whether
+ or not the export was successful.
+
+ \sa shaderCacheExport(), shaderCacheFile
+ */
+
+/*!
This function is for backwards compatibility. We recommend using \l{DataInput}s to control
slide changes. \l{DataInput} provides stronger contract between the design and
code as it avoids use of elementPath (a reference to design's internal structure).
@@ -1626,11 +1786,12 @@ void Q3DSPresentationPrivate::setCommandQueue(CommandQueue *queue)
if (m_commandQueue) {
setDelayedLoading(m_delayedLoading);
setVariantList(m_variantList);
+ setShaderCacheFile(m_shaderCacheFile);
// Queue a request ASAP for datainputs and outputs defined in UIA file so that
// getDataInputs has up-to-date info at the earliest and that data outputs
// connect from source to destination
- m_commandQueue->queueCommand({}, CommandType_RequestDataInputs);
- m_commandQueue->queueCommand({}, CommandType_RequestDataOutputs);
+ m_commandQueue->queueCommand(CommandType_RequestDataInputs);
+ m_commandQueue->queueCommand(CommandType_RequestDataOutputs);
setSource(m_source);
}
}
@@ -1655,12 +1816,21 @@ void Q3DSPresentationPrivate::setDataInputDirty(const QString &name, bool dirty)
m_dataInputs[name]->d_ptr->setDirty(dirty);
}
+void Q3DSPresentationPrivate::setShaderCacheFile(const QUrl &fileName)
+{
+ m_shaderCacheFile = fileName;
+ if (m_commandQueue) {
+ m_commandQueue->m_shaderCacheFile = fileName;
+ m_commandQueue->m_shaderCacheFileChanged = true;
+ }
+}
+
void Q3DSPresentationPrivate::requestResponseHandler(CommandType commandType, void *requestData)
{
+ QVariantList *response = reinterpret_cast<QVariantList *>(requestData);
+
switch (commandType) {
case CommandType_RequestDataInputs: {
- QVariantList *response = reinterpret_cast<QVariantList *>(requestData);
-
for (int i = 0; i < response->size(); ++i) {
// Check and append to QML-side list if the (UIA) presentation has additional datainputs
// that are not explicitly defined in QML code.
@@ -1680,27 +1850,100 @@ void Q3DSPresentationPrivate::requestResponseHandler(CommandType commandType, vo
m_dataInputs[receivedDI->name()]->d_ptr->m_metadata = receivedDI->d_ptr->m_metadata;
}
}
- delete response;
Q_EMIT q_ptr->dataInputsReady();
break;
}
case CommandType_RequestDataOutputs: {
- QVariantList *response = reinterpret_cast<QVariantList *>(requestData);
-
for (int i = 0; i < response->size(); ++i) {
// Check and append to QML-side list if the (UIA) presentation has additional
// dataoutputs that are not explicitly defined in QML code.
if (!m_dataOutputs.contains(response->at(i).value<QString>()))
registerDataOutput(new Q3DSDataOutput(response->at(i).value<QString>(), nullptr));
}
- delete response;
Q_EMIT q_ptr->dataOutputsReady();
break;
}
+ case CommandType_RequestExportShaderCache: {
+ if (response->size() > 0)
+ m_shaderCacheExport = response->at(0).toByteArray();
+ if (!m_shaderCacheExport.isEmpty())
+ m_shaderCacheExport = qCompress(m_shaderCacheExport);
+ if (!m_shaderCacheWritePending.isEmpty()) {
+ writeShaderCache(m_shaderCacheWritePending);
+ m_shaderCacheWritePending.clear();
+ }
+ if (m_shaderCacheDumpPending) {
+ m_shaderCacheDumpPending = false;
+ dumpShaderCache();
+ }
+ break;
+ }
default:
Q_ASSERT(false);
break;
}
+ delete response;
+}
+
+// Writes current shader cache to the specified file in UTF-8 format
+void Q3DSPresentationPrivate::writeShaderCache(const QUrl &shaderCacheFile)
+{
+ if (m_shaderCacheExport.isEmpty())
+ return; // Warning is already printed by export function
+ const QString filePath = shaderCacheFile.toLocalFile();
+ QSaveFile file(filePath);
+ QFileInfo(filePath).dir().mkpath(QStringLiteral("."));
+ bool success = false;
+ if (file.open(QIODevice::WriteOnly) && file.write(m_shaderCacheExport) != -1) {
+ file.commit();
+ success = true;
+ } else {
+ qWarning() << __FUNCTION__ << "Warning: Failed to write shader cache:"
+ << shaderCacheFile << file.errorString();
+ }
+ Q_EMIT q_ptr->shaderCacheExported(success);
+}
+
+QByteArray Q3DSPresentationPrivate::loadShaderCache() const
+{
+ if (!m_shaderCacheFile.isEmpty()) {
+ QFile file(Q3DSUtils::urlToLocalFileOrQrc(m_shaderCacheFile));
+ if (file.open(QIODevice::ReadOnly))
+ return qUncompress(file.readAll());
+
+ qWarning() << __FUNCTION__ << "Warning: Failed to read shader cache:"
+ << m_shaderCacheFile << file.errorString();
+ }
+ return {};
+}
+
+void Q3DSPresentationPrivate::exportShaderCache(bool binaryShaders, bool dumpCache)
+{
+ if (m_viewerApp) {
+ m_shaderCacheExport = m_viewerApp->exportShaderCache(binaryShaders);
+ if (!m_shaderCacheExport.isEmpty())
+ m_shaderCacheExport = qCompress(m_shaderCacheExport);
+ if (dumpCache)
+ dumpShaderCache();
+ } else if (m_commandQueue) {
+ m_commandQueue->queueCommand(CommandType_RequestExportShaderCache, binaryShaders);
+ m_shaderCacheDumpPending = dumpCache;
+ }
+}
+
+void Q3DSPresentationPrivate::dumpShaderCache()
+{
+ if (!m_shaderCacheExport.isEmpty()) {
+ // Can't just dump the whole thing into a single qWarning() call, since at least on
+ // windows long strings are not printed out. qWarning() is used to make the dump go to
+ // stderr, which is less likely to get cluttered with other messages.
+ qWarning() << "-- Shader cache base64 dump start --";
+ const QString cacheDump = QString::fromLatin1(m_shaderCacheExport.toBase64());
+ for (int i = 0; i < cacheDump.size(); i += 100)
+ qWarning().noquote() << cacheDump.mid(i, 100);
+ qWarning() << "-- Shader cache base64 dump end --";
+ }
+ Q_EMIT q_ptr->shaderCacheExported(!m_shaderCacheExport.isEmpty());
}
// Doc note: The ownership of the registered scenes remains with the caller, who needs to
diff --git a/src/api/studio3d/q3dspresentation.h b/src/api/studio3d/q3dspresentation.h
index 91e76c5..af84073 100644
--- a/src/api/studio3d/q3dspresentation.h
+++ b/src/api/studio3d/q3dspresentation.h
@@ -58,6 +58,7 @@ class Q_STUDIO3D_EXPORT Q3DSPresentation : public QObject
Q_PROPERTY(QStringList createdElements READ createdElements NOTIFY elementsCreated)
Q_PROPERTY(QStringList createdMaterials READ createdMaterials NOTIFY materialsCreated)
Q_PROPERTY(QStringList createdMeshes READ createdMeshes NOTIFY meshesCreated)
+ Q_PROPERTY(QUrl shaderCacheFile READ shaderCacheFile WRITE setShaderCacheFile NOTIFY shaderCacheFileChanged )
public:
explicit Q3DSPresentation(QObject *parent = nullptr);
@@ -90,6 +91,10 @@ public:
Q_INVOKABLE void preloadSlide(const QString &elementPath);
Q_INVOKABLE void unloadSlide(const QString &elementPath);
+ Q_INVOKABLE void exportShaderCache(const QUrl &shaderCacheFile, bool binaryShaders);
+ Q_INVOKABLE void exportShaderCache(bool binaryShaders);
+ QUrl shaderCacheFile() const;
+
// Input event handlers
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
@@ -131,6 +136,7 @@ public Q_SLOTS:
void fireEvent(const QString &elementPath, const QString &eventName);
void setGlobalAnimationTime(qint64 milliseconds);
void setDataInputValue(const QString &name, const QVariant &value, bool force = false);
+ void setShaderCacheFile(const QUrl &fileName);
Q_SIGNALS:
void variantListChanged(const QStringList &variantList);
@@ -144,6 +150,8 @@ Q_SIGNALS:
void elementsCreated(const QStringList &elementPaths, const QString &error);
void materialsCreated(const QStringList &materialNames, const QString &error);
void meshesCreated(const QStringList &meshNames, const QString &error);
+ void shaderCacheFileChanged(const QUrl &fileName);
+ void shaderCacheExported(bool success);
private:
Q_DISABLE_COPY(Q3DSPresentation)
diff --git a/src/api/studio3d/q3dspresentation_p.h b/src/api/studio3d/q3dspresentation_p.h
index 5ade08e..45231b4 100644
--- a/src/api/studio3d/q3dspresentation_p.h
+++ b/src/api/studio3d/q3dspresentation_p.h
@@ -73,6 +73,7 @@ public:
void setDelayedLoading(bool enable);
void setDataInputsChanged(bool changed);
void setDataInputDirty(const QString &name, bool dirty);
+ void setShaderCacheFile(const QUrl &fileName);
void registerElement(Q3DSElement *element);
void unregisterElement(Q3DSElement *element);
@@ -100,6 +101,11 @@ public:
void requestResponseHandler(CommandType commandType, void *requestData);
+ void writeShaderCache(const QUrl &shaderCacheFile);
+ QByteArray loadShaderCache() const;
+ void exportShaderCache(bool binaryShaders, bool dumpCache);
+ void dumpShaderCache();
+
public Q_SLOTS:
void handleSlideEntered(const QString &elementPath, unsigned int index, const QString &name);
void handleDataOutputValueUpdate(const QString &name, const QVariant &newValue);
@@ -124,6 +130,10 @@ private:
QStringList m_createdMaterials;
QStringList m_createdMeshes;
bool m_dataInputsChanged;
+ QUrl m_shaderCacheFile;
+ QByteArray m_shaderCacheExport;
+ QUrl m_shaderCacheWritePending;
+ bool m_shaderCacheDumpPending = false;
friend class Q3DSStudio3D;
};
diff --git a/src/api/studio3d/q3dssurfaceviewer.cpp b/src/api/studio3d/q3dssurfaceviewer.cpp
index 1ffad89..e885a4b 100644
--- a/src/api/studio3d/q3dssurfaceviewer.cpp
+++ b/src/api/studio3d/q3dssurfaceviewer.cpp
@@ -662,6 +662,7 @@ bool Q3DSSurfaceViewerPrivate::initializeRuntime()
m_context->format(), int(m_fboId), localSource,
m_presentation->variantList(),
m_presentation->delayedLoading(), true,
+ m_presentation->d_ptr->loadShaderCache(),
m_presentation->d_ptr->streamProxy())) {
setError(m_viewerApp->error());
releaseRuntime();
diff --git a/src/api/studio3dqml/q3dsrenderer.cpp b/src/api/studio3dqml/q3dsrenderer.cpp
index 274c691..5a99aad 100644
--- a/src/api/studio3dqml/q3dsrenderer.cpp
+++ b/src/api/studio3dqml/q3dsrenderer.cpp
@@ -104,8 +104,11 @@ void Q3DSRenderer::synchronize(QQuickFramebufferObject *inView)
m_presentation->setVariantList(m_commands.m_variantList);
m_presentation->setSource(m_commands.m_source);
m_presentation->setDelayedLoading(m_commands.m_delayedLoading);
+ m_presentation->setShaderCacheFile(m_commands.m_shaderCacheFile);
m_commands.m_sourceChanged = false;
m_commands.m_variantListChanged = false;
+ m_commands.m_delayedLoadingChanged = false;
+ m_commands.m_shaderCacheFileChanged = false;
m_initialized = false;
m_initializationFailure = false;
m_error.clear();
@@ -243,7 +246,7 @@ bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
m_runtime, theWidth, theHeight, QOpenGLContext::currentContext()->format(),
int(inFbo->handle()), localSource, m_presentation->variantList(),
m_presentation->delayedLoading(), m_visitor, context,
- m_asyncInitSurface);
+ m_asyncInitSurface, m_presentation->d_ptr->loadShaderCache());
connect(m_runtimeInitializerThread, &Q3DSRuntimeInitializerThread::initDone,
this, &Q3DSRenderer::handleRuntimeInitializedAsync, Qt::QueuedConnection);
context->moveToThread(m_runtimeInitializerThread);
@@ -254,6 +257,7 @@ bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
int(inFbo->handle()), localSource,
m_presentation->variantList(),
m_presentation->delayedLoading(), true,
+ m_presentation->d_ptr->loadShaderCache(),
m_visitor)) {
m_error = m_runtime->error();
releaseRuntime();
@@ -472,6 +476,12 @@ void Q3DSRenderer::processCommands()
command.m_data = nullptr;
break;
}
+ case CommandType_PreloadSlide:
+ m_runtime->preloadSlide(cmd.m_elementPath);
+ break;
+ case CommandType_UnloadSlide:
+ m_runtime->unloadSlide(cmd.m_elementPath);
+ break;
case CommandType_RequestSlideInfo: {
int current = 0;
int previous = 0;
@@ -486,7 +496,6 @@ void Q3DSRenderer::processCommands()
requestData->append(QVariant(previousName));
Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
-
break;
}
case CommandType_RequestDataInputs: {
@@ -518,12 +527,15 @@ void Q3DSRenderer::processCommands()
Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
break;
}
- case CommandType_PreloadSlide:
- m_runtime->preloadSlide(cmd.m_elementPath);
- break;
- case CommandType_UnloadSlide:
- m_runtime->unloadSlide(cmd.m_elementPath);
+ case CommandType_RequestExportShaderCache: {
+ QByteArray shaderCache = m_runtime->exportShaderCache(cmd.m_boolValue);
+ QVariantList *requestData = new QVariantList();
+ requestData->append(QVariant(shaderCache));
+
+ Q_EMIT requestResponse({}, cmd.m_commandType, requestData);
break;
+ }
+
default:
qWarning() << __FUNCTION__ << "Unrecognized CommandType in command list!";
}
diff --git a/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp b/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp
index 677b61a..bc021aa 100644
--- a/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp
+++ b/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp
@@ -39,7 +39,7 @@ Q3DSRuntimeInitializerThread::Q3DSRuntimeInitializerThread(
Q3DSViewer::Q3DSViewerApp *runtime,
int width, int height, const QSurfaceFormat &format, int offscreenID, const QString &source,
const QStringList &variantList, bool delayedLoading, qt3ds::Qt3DSAssetVisitor *assetVisitor,
- QOpenGLContext *context, QSurface *surface)
+ QOpenGLContext *context, QSurface *surface, const QByteArray &shaderCache)
: m_runtime(runtime)
, m_width(width)
, m_height(height)
@@ -51,6 +51,7 @@ Q3DSRuntimeInitializerThread::Q3DSRuntimeInitializerThread(
, m_assetVisitor(assetVisitor)
, m_context(context)
, m_surface(surface)
+ , m_shaderCache(shaderCache)
{
}
@@ -60,7 +61,7 @@ void Q3DSRuntimeInitializerThread::run()
m_context->makeCurrent(m_surface);
m_success = m_runtime->InitializeApp(m_width, m_height, m_format, m_offscreenId,
m_source, m_variantList, m_delayedLoading, false,
- m_assetVisitor);
+ m_shaderCache, m_assetVisitor);
m_context->doneCurrent();
delete m_context;
diff --git a/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h b/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h
index 42dcf67..9aba691 100644
--- a/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h
+++ b/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h
@@ -64,7 +64,7 @@ public:
int offscreenID, const QString &source,
const QStringList &variantList, bool delayedLoading,
qt3ds::Qt3DSAssetVisitor *assetVisitor, QOpenGLContext *context,
- QSurface *surface);
+ QSurface *surface, const QByteArray &shaderCache);
void run() override;
@@ -86,6 +86,7 @@ private:
qt3ds::Qt3DSAssetVisitor *m_assetVisitor;
QOpenGLContext *m_context;
QSurface *m_surface;
+ QByteArray m_shaderCache;
bool m_success = false;
};
diff --git a/src/api/studio3dqml/q3dsstudio3d.cpp b/src/api/studio3dqml/q3dsstudio3d.cpp
index 19cf09b..4cb0850 100644
--- a/src/api/studio3dqml/q3dsstudio3d.cpp
+++ b/src/api/studio3dqml/q3dsstudio3d.cpp
@@ -366,7 +366,11 @@ void Q3DSStudio3D::reset()
m_pendingCommands.m_sourceChanged = true;
m_pendingCommands.m_source = m_presentation ? m_presentation->source() : QString();
m_pendingCommands.m_variantListChanged = true;
- m_pendingCommands.m_variantList = m_presentation ? m_presentation->variantList() : QStringList();
+ m_pendingCommands.m_variantList = m_presentation ? m_presentation->variantList()
+ : QStringList();
+ m_pendingCommands.m_shaderCacheFileChanged = true;
+ m_pendingCommands.m_shaderCacheFile = m_presentation ? m_presentation->shaderCacheFile()
+ : QString();
}
/*!
@@ -385,23 +389,16 @@ void Q3DSStudio3D::requestResponseHandler(const QString &elementPath, CommandTyp
qWarning() << __FUNCTION__ << "RequestSlideInfo response got for unregistered scene.";
break;
}
- case CommandType_RequestDataInputs: {
+ case CommandType_RequestDataInputs:
+ case CommandType_RequestDataOutputs:
+ case CommandType_RequestExportShaderCache:
+ {
Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
if (handler) {
handler->d_ptr->requestResponseHandler(commandType, requestData);
} else {
- qWarning() << __FUNCTION__
- << "RequestDataInputs response got for invalid presentation.";
- }
- break;
- }
- case CommandType_RequestDataOutputs: {
- Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
- if (handler) {
- handler->d_ptr->requestResponseHandler(commandType, requestData);
- } else {
- qWarning() << __FUNCTION__
- << "RequestDataOutputs response got for invalid presentation.";
+ qWarning() << __FUNCTION__ << "Command " << commandType
+ << "response got for invalid presentation.";
}
break;
}