summaryrefslogtreecommitdiffstats
path: root/customcontext
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2014-03-05 08:33:05 +0100
committerGunnar Sletta <gunnar.sletta@jollamobile.com>2014-03-06 08:44:14 +0100
commit488a8184b90801f3987779b5b1b046cf67ba0d4b (patch)
tree202d150461977ffee30f6aa9f64b3e20c2625672 /customcontext
parentc4dc0ac41b9efa020be99ae604d6a12431d7d8c1 (diff)
Safeguard program binaries from filling up the filesystem.
Most QML applications will never have this problem as they use a small amount of shaders and the cache will reach a max of 20-30 shaders. This is only a safeguard against applications which recompile new shaders all the time. Change-Id: If6dbb6da4eff82e2a4e43a9414a45a7bf4ce762a Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Diffstat (limited to 'customcontext')
-rw-r--r--customcontext/programbinary.cpp66
1 files changed, 65 insertions, 1 deletions
diff --git a/customcontext/programbinary.cpp b/customcontext/programbinary.cpp
index ac331fd..b8424e7 100644
--- a/customcontext/programbinary.cpp
+++ b/customcontext/programbinary.cpp
@@ -45,6 +45,7 @@
#include <QtCore/QFile>
#include <QtCore/QSaveFile>
#include <QtCore/QDir>
+#include <QtCore/QDateTime>
#include <QtCore/QElapsedTimer>
#include <QtQuick/qsgmaterial.h>
@@ -98,12 +99,24 @@ struct ProgramBinary
QByteArray fsh;
};
+int get_env_int(const char *name, int defaultValue)
+{
+ QByteArray v = qgetenv(name);
+ bool ok;
+ int value = v.toInt(&ok);
+ if (!ok)
+ value = defaultValue;
+ return value;
+}
+
class ProgramBinaryStore
{
public:
ProgramBinaryStore()
: m_hash(QCryptographicHash::Sha1)
{
+ m_maxShaderCount = get_env_int("QSG_PROGRAM_BINARY_LIMIT", 512);
+
m_location = QString::fromLocal8Bit(qgetenv("QSG_PROGRAM_BINARY_STORE"));
if (m_location.isEmpty()) {
QString base = QString::fromLocal8Bit(qgetenv("XDG_RUNTIME_DIR"));
@@ -136,6 +149,8 @@ public:
void insert(ProgramBinary *shader);
void purge(const QByteArray &key);
+ void sanityCheck();
+
void compileAndInsert(QSGRenderContext *rc, const QByteArray &key, QSGMaterialShader *s, QSGMaterial *m, const char *v, const char *f);
private:
@@ -145,6 +160,8 @@ private:
QString m_location;
+ int m_maxShaderCount;
+
static ProgramBinaryStore *instance;
};
@@ -182,7 +199,7 @@ ProgramBinary *ProgramBinaryStore::lookup(const QByteArray key)
void ProgramBinaryStore::insert(ProgramBinary *shader)
{
- QMutexLocker lock(&m_mutex);
+ m_mutex.lock();
m_store.insert(shader->key, shader);
@@ -193,6 +210,10 @@ void ProgramBinaryStore::insert(ProgramBinary *shader)
stream << shader->blob;
file.commit();
}
+
+ m_mutex.unlock();
+
+ sanityCheck();
}
void ProgramBinaryStore::purge(const QByteArray &key)
@@ -273,4 +294,47 @@ void RenderContext::compile(QSGMaterialShader *shader, QSGMaterial *material, co
}
}
+static bool sortByAccessTime(const QFileInfo &a, const QFileInfo &b)
+{
+ return a.lastRead() < b.lastRead();
+}
+
+/* The primary goal of the sanity check is that we should not
+ * pollute the file system with an infinite amount of shaders,
+ * even if each one is fairly small.
+ *
+ * Pollution can quite easily happen because of QML and ShaderEffect.
+ * For instance, if an application has a shader effect editor which
+ * changes the fragment/vertex strings every few seconds the file system
+ * will fill up with thousands of unused shaders. Better to nuke them.
+ *
+ * If an app has "many" shaders check if the amount on disk is
+ * more than maxShaderCount. If so, delete them so we are left with
+ * maxShaderCount/2. We also nuke the store, as the programs
+ * themselves are anyway cached by the renderers and recovering them
+ * from disk again is cheapish.
+ *
+ * Multiple processes with different maxShaderCount will work against
+ * different counts, so they might end up conflicting, but the default
+ * value is set high enough for this to not be a problem and since the
+ * store is user-local. If he/she changes it to a low value, it is their
+ * problem.
+ */
+void ProgramBinaryStore::sanityCheck()
+{
+ if (m_store.size() > m_maxShaderCount) {
+ QDir dir(m_location);
+ QList<QFileInfo> infos = dir.entryInfoList(QDir::Files);
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug() << " - BinaryProgramStore has" << m_store.size() << "entries in process," << infos.size() << "on disk..." << m_maxShaderCount;
+#endif
+ if (infos.size()) {
+ std::sort(&infos.first(), &infos.last() + 1, sortByAccessTime);
+ int firstToKeep = infos.size() - m_maxShaderCount / 2;
+ for (int i=0; i<firstToKeep; ++i)
+ purge(infos.at(i).fileName().toLocal8Bit());
+ }
+ }
+}
+
}