aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2021-01-20 12:13:56 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2021-01-25 10:13:08 +0100
commit8d565f177135a780c9f6238b6376252d5517c53f (patch)
tree98b0b95e2d40b6c4c62c0c51237cdfef92a49921
parent8eac7e747623c95379735b63e61d99b17132fecd (diff)
Add env.vars. to toggle pipeline cache load/save
QRhi has APIs (but private ones) that allow retrieving and restoring the contents of the "pipeline cache". (which may map directly to VkPipelineCache, or may be a simulated, OpenGL program binary based solution) In many cases it is convenient if the saving of the cache blob to a file, and then, during subsequent runs of the application, the loading of cache contents, can be enabled via environment variables: QSG_RHI_PIPELINE_CACHE_SAVE=filename maps to setting the EnablePipelineCacheDataSave flag on the QRhi, and writing the collected data to file upon application exit. (more correctly, when the QRhi is about to be destroyed by the render loop) QSG_RHI_PIPELINE_CACHE_LOAD=filename maps to attempting to read the contents of the specified file, and, if successful, passing it to QRhi right after initialization. When supported and the data is not corrupt or incomplete, the result is likely improved pipeline creation times (the exact details depend on the driver with Vulkan, while with OpenGL it all maps to glProgramBinary instead of compiling from source) Setting QSG_INFO=1 can be useful to see what is happening when the above 2 env.vars. are set. With OpenGL the simulated "pipeline cache" is orthogonal to the Qt 5 era shader program disk cache: loading from both is supported transparently to the application. When QSG_RHI_PIPELINE_CACHE_SAVE is enabled, the disk cache will not be written to. Task-number: QTBUG-90398 Change-Id: I82d9a81e9dab39d3513a6aa7c6e1ff748a4ec6e5 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r--src/quick/items/qquickrendercontrol.cpp2
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp52
-rw-r--r--src/quick/scenegraph/qsgrhisupport_p.h3
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp4
5 files changed, 57 insertions, 8 deletions
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index d71af669f0..caf5a17dc6 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -666,7 +666,7 @@ bool QQuickRenderControlPrivate::initRhi()
void QQuickRenderControlPrivate::resetRhi()
{
- delete rhi;
+ QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
delete offscreenSurface;
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index cf41868dc3..077814b1f4 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -376,7 +376,7 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
if (m_windows.size() == 0) {
rc->invalidate();
d->rhi = nullptr;
- delete rhi;
+ QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
delete offscreenSurface;
offscreenSurface = nullptr;
@@ -402,7 +402,7 @@ void QSGGuiThreadRenderLoop::handleDeviceLoss()
it->rhiDeviceLost = true;
}
- delete rhi;
+ QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
}
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index 7d37d405b1..189cf0cba8 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -205,6 +205,11 @@ void QSGRhiSupport::applySettings()
// EnableProfiling + DebugMarkers
m_profile = uint(qEnvironmentVariableIntValue("QSG_RHI_PROFILE"));
+ // EnablePipelineCacheDataSave
+ m_pipelineCacheSave = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_SAVE");
+
+ m_pipelineCacheLoad = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_LOAD");
+
m_shaderEffectDebug = uint(qEnvironmentVariableIntValue("QSG_RHI_SHADEREFFECT_DEBUG"));
m_preferSoftwareRenderer = uint(qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"));
@@ -215,8 +220,11 @@ void QSGRhiSupport::applySettings()
const QString backendName = rhiBackendName();
qCDebug(QSG_LOG_INFO,
- "Using QRhi with backend %s\n graphics API debug/validation layers: %d\n QRhi profiling and debug markers: %d",
- qPrintable(backendName), m_debugLayer, m_profile);
+ "Using QRhi with backend %s\n"
+ " Graphics API debug/validation layers: %d\n"
+ " QRhi profiling and debug markers: %d\n"
+ " Shader/pipeline cache collection: %d",
+ qPrintable(backendName), m_debugLayer, m_profile, !m_pipelineCacheSave.isEmpty());
if (m_preferSoftwareRenderer)
qCDebug(QSG_LOG_INFO, "Prioritizing software renderers");
}
@@ -576,6 +584,8 @@ QRhi *QSGRhiSupport::createRhi(QQuickWindow *window, QOffscreenSurface *offscree
flags |= QRhi::EnableProfiling | QRhi::EnableDebugMarkers;
if (isSoftwareRendererRequested())
flags |= QRhi::PreferSoftwareRenderer;
+ if (!m_pipelineCacheSave.isEmpty())
+ flags |= QRhi::EnablePipelineCacheDataSave;
const QRhi::Implementation backend = rhiBackend();
if (backend == QRhi::Null) {
@@ -682,12 +692,48 @@ QRhi *QSGRhiSupport::createRhi(QQuickWindow *window, QOffscreenSurface *offscree
}
#endif
- if (!rhi)
+ if (!rhi) {
qWarning("Failed to create RHI (backend %d)", backend);
+ return nullptr;
+ }
+
+ if (!m_pipelineCacheLoad.isEmpty()) {
+ QFile f(m_pipelineCacheLoad);
+ if (f.open(QIODevice::ReadOnly)) {
+ qCDebug(QSG_LOG_INFO, "Attempting to seed pipeline cache from '%s'",
+ qPrintable(m_pipelineCacheLoad));
+ rhi->setPipelineCacheData(f.readAll());
+ } else {
+ qWarning("Could not open pipeline cache source file '%s'",
+ qPrintable(m_pipelineCacheLoad));
+ }
+ }
return rhi;
}
+void QSGRhiSupport::destroyRhi(QRhi *rhi)
+{
+ if (!rhi)
+ return;
+
+ if (!rhi->isDeviceLost()) {
+ if (!m_pipelineCacheSave.isEmpty()) {
+ QFile f(m_pipelineCacheSave);
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qCDebug(QSG_LOG_INFO, "Writing pipeline cache contents to '%s'",
+ qPrintable(m_pipelineCacheSave));
+ f.write(rhi->pipelineCacheData());
+ } else {
+ qWarning("Could not open pipeline cache output file '%s'",
+ qPrintable(m_pipelineCacheSave));
+ }
+ }
+ }
+
+ delete rhi;
+}
+
QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src)
{
Q_ASSERT(rhi->isRecordingFrame());
diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h
index f144a47a6a..73fa2caad1 100644
--- a/src/quick/scenegraph/qsgrhisupport_p.h
+++ b/src/quick/scenegraph/qsgrhisupport_p.h
@@ -127,6 +127,7 @@ public:
QOffscreenSurface *maybeCreateOffscreenSurface(QWindow *window);
QRhi *createRhi(QQuickWindow *window, QOffscreenSurface *offscreenSurface);
+ void destroyRhi(QRhi *rhi);
void prepareWindowForRhi(QQuickWindow *window);
QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src = nullptr);
@@ -146,6 +147,8 @@ private:
} m_requested;
QRhi::Implementation m_rhiBackend = QRhi::Null;
int m_killDeviceFrameCount;
+ QString m_pipelineCacheSave;
+ QString m_pipelineCacheLoad;
uint m_settingsApplied : 1;
uint m_enableRhi : 1;
uint m_debugLayer : 1;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 9b520d53f2..8a0202ede9 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -556,7 +556,7 @@ void QSGRenderThread::invalidateGraphics(QQuickWindow *window, bool inDestructor
window, dd->swapchain);
}
}
- delete rhi;
+ QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- QRhi destroyed");
} else {
@@ -637,7 +637,7 @@ void QSGRenderThread::handleDeviceLoss()
sgrc->invalidate();
wm->releaseSwapchain(window);
rhiDeviceLost = true;
- delete rhi;
+ QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
}