diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-01-20 12:13:56 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-01-25 10:13:08 +0100 |
commit | 8d565f177135a780c9f6238b6376252d5517c53f (patch) | |
tree | 98b0b95e2d40b6c4c62c0c51237cdfef92a49921 | |
parent | 8eac7e747623c95379735b63e61d99b17132fecd (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.cpp | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop.cpp | 4 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrhisupport.cpp | 52 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrhisupport_p.h | 3 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop.cpp | 4 |
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; } |