sg: Limit automatic pipeline cache writes

...based on the window flags.

As the docs already describe, for full control one can assign cache
files explicitly to each QQuickWindow. (of course, that is not always
trivial esp. when working with the QML API but let's not go there now)
This does not affect that. The default, automatic cache however needs
to apply some simple guesses as to when it does not make sense to
bother with loading/saving the cache. Otherwise we'd end up with
silly situations, when using the default threaded render loop at
least, where showing/destroying a tooltip (if it's a standalone
window) kicks off file I/O for the pipeline cache, with likely
very limited benefits (and whatever it collects is lost later
when the main (last) window is closed anyway).

In addition, make some of the logs more readable by including
which QRhi and which QQuickWindow are the messages talking about.
This becomes pretty important in applications dealing with
multiple windows over their lifetime.

Change-Id: I9cabe3eb0db994e5c1d73ca071664ff1bf5f0d45
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
Laszlo Agocs 2022-09-19 14:24:37 +02:00
parent 8f89a4993c
commit b01e4ce2b2
2 changed files with 49 additions and 23 deletions

View File

@ -948,19 +948,34 @@ static inline QString automaticPipelineCacheFileName(QRhi *rhi)
return QString();
}
static inline bool isAutomaticPipelineCacheLoadSkippedForWindow(Qt::WindowFlags wflags)
{
return wflags.testFlag(Qt::ToolTip) || wflags.testFlag(Qt::SplashScreen);
}
static inline bool isAutomaticPipelineCacheSaveSkippedForWindow(Qt::WindowFlags wflags)
{
// this catches Tool, ToolTip, SplashScreen as well
return wflags.testFlag(Qt::Dialog) || wflags.testFlag(Qt::Popup);
}
static inline QString pipelineCacheLockFileName(const QString &name)
{
return name + QLatin1String(".lck");
}
void QSGRhiSupport::preparePipelineCache(QRhi *rhi, const QQuickGraphicsConfiguration &config)
void QSGRhiSupport::preparePipelineCache(QRhi *rhi, QQuickWindow *window)
{
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
// the explicitly set filename always takes priority as per docs
QString pipelineCacheLoad = config.pipelineCacheLoadFile();
QString pipelineCacheLoad = wd->graphicsConfig.pipelineCacheLoadFile();
bool isAutomatic = false;
if (pipelineCacheLoad.isEmpty() && config.isAutomaticPipelineCacheEnabled()) {
pipelineCacheLoad = automaticPipelineCacheFileName(rhi);
isAutomatic = true;
if (pipelineCacheLoad.isEmpty() && wd->graphicsConfig.isAutomaticPipelineCacheEnabled()) {
if (!isAutomaticPipelineCacheLoadSkippedForWindow(window->flags())) {
pipelineCacheLoad = automaticPipelineCacheFileName(rhi);
isAutomatic = true;
}
}
if (pipelineCacheLoad.isEmpty())
@ -982,17 +997,19 @@ void QSGRhiSupport::preparePipelineCache(QRhi *rhi, const QQuickGraphicsConfigur
return;
}
qCDebug(QSG_LOG_INFO, "Attempting to seed pipeline cache from '%s'",
qPrintable(pipelineCacheLoad));
rhi->setPipelineCacheData(f.readAll());
const QByteArray buf = f.readAll();
if (!buf.isEmpty()) {
qCDebug(QSG_LOG_INFO, "Attempting to seed pipeline cache for QRhi %p from '%s'",
rhi, qPrintable(pipelineCacheLoad));
rhi->setPipelineCacheData(buf);
}
}
void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfiguration &config)
{
// output the rhi statistics about pipelines, as promised by the documentation
qCDebug(QSG_LOG_INFO, "Total time spent on pipeline creation during the lifetime of the QRhi was %lld ms",
rhi->statistics().totalPipelineCreationTime);
qCDebug(QSG_LOG_INFO, "Total time spent on pipeline creation during the lifetime of the QRhi %p was %lld ms",
rhi, rhi->statistics().totalPipelineCreationTime);
// the explicitly set filename always takes priority as per docs
QString pipelineCacheSave = config.pipelineCacheSaveFile();
@ -1005,6 +1022,13 @@ void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfigu
if (pipelineCacheSave.isEmpty())
return;
const QByteArray buf = rhi->pipelineCacheData();
// If empty, do nothing. This is exactly what will happen if the rhi was
// created without QRhi::EnablePipelineCacheDataSave set.
if (buf.isEmpty())
return;
QLockFile lock(pipelineCacheLockFileName(pipelineCacheSave));
if (!lock.lock()) {
qWarning("Could not create pipeline cache lock file '%s'",
@ -1026,9 +1050,8 @@ void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfigu
return;
}
const QByteArray buf = rhi->pipelineCacheData();
qCDebug(QSG_LOG_INFO, "Writing pipeline cache contents (%d bytes) to '%s'",
int(buf.size()), qPrintable(pipelineCacheSave));
qCDebug(QSG_LOG_INFO, "Writing pipeline cache contents (%d bytes) for QRhi %p to '%s'",
int(buf.size()), rhi, qPrintable(pipelineCacheSave));
if (f.write(buf) != buf.size()
#if QT_CONFIG(temporaryfile)
@ -1053,7 +1076,7 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Rhi) {
rhi = customDevD->u.rhi;
if (rhi) {
preparePipelineCache(rhi, wd->graphicsConfig);
preparePipelineCache(rhi, window);
return { rhi, false };
}
}
@ -1061,17 +1084,18 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
const bool debugLayer = wd->graphicsConfig.isDebugLayerEnabled();
const bool debugMarkers = wd->graphicsConfig.isDebugMarkersEnabled();
const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice();
const bool pipelineCacheSave = wd->graphicsConfig.isAutomaticPipelineCacheEnabled()
|| !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty();
const bool pipelineCacheSave = !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty()
|| (wd->graphicsConfig.isAutomaticPipelineCacheEnabled()
&& !isAutomaticPipelineCacheSaveSkippedForWindow(window->flags()));
const QString backendName = rhiBackendName();
qCDebug(QSG_LOG_INFO,
"Creating QRhi with backend %s for window %p\n"
"Creating QRhi with backend %s for window %p (wflags 0x%X)\n"
" Graphics API debug/validation layers: %d\n"
" Debug markers: %d\n"
" Prefer software device: %d\n"
" Shader/pipeline cache collection: %d",
qPrintable(backendName), window, debugLayer, debugMarkers, preferSoftware, pipelineCacheSave);
qPrintable(backendName), window, int(window->flags()), debugLayer, debugMarkers, preferSoftware, pipelineCacheSave);
QRhi::Flags flags;
if (debugMarkers)
@ -1191,10 +1215,12 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
}
#endif
if (rhi)
preparePipelineCache(rhi, wd->graphicsConfig);
else
if (rhi) {
qCDebug(QSG_LOG_INFO, "Created QRhi %p for window %p", rhi, window);
preparePipelineCache(rhi, window);
} else {
qWarning("Failed to create RHI (backend %d)", backend);
}
return { rhi, true };
}

View File

@ -113,7 +113,7 @@ private:
QSGRhiSupport();
void applySettings();
void adjustToPlatformQuirks();
void preparePipelineCache(QRhi *rhi, const QQuickGraphicsConfiguration &config);
void preparePipelineCache(QRhi *rhi, QQuickWindow *window);
void finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfiguration &config);
struct {
bool valid = false;