aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/util
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2018-07-08 11:23:24 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2018-08-17 11:06:20 +0000
commit36c6b727c5f433ce3f22e18d93e2502df1c526aa (patch)
tree4c57debdf593897440d9d012935bfca16ba7cb66 /src/quick/scenegraph/util
parent9fbdc8c4c2c028427b19907d636a7a83d79cbd09 (diff)
Load pregenerated glyph cache in default DF cache
In order to support quick loading of scenes with lots of text, we support preloading the contents of the distance field cache from a generated file instead of creating all the distance fields on startup. The idea is that when creating a distance field cache for a specific font, the data will be prepopulated. This is stored in a table in the font file and is picked up automatically by Qt when available. [ChangeLog][Text] Support pregenerated loading distance field glyph caches to decrease startup time for applications with large amounts of text. Task-number: QTBUG-69356 Change-Id: I7cff0c4c782f819b1c893041405970ea4553fb8d Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/quick/scenegraph/util')
-rw-r--r--src/quick/scenegraph/util/qsgareaallocator.cpp144
-rw-r--r--src/quick/scenegraph/util/qsgareaallocator_p.h4
2 files changed, 148 insertions, 0 deletions
diff --git a/src/quick/scenegraph/util/qsgareaallocator.cpp b/src/quick/scenegraph/util/qsgareaallocator.cpp
index cd270a1d63..9a8c8e333b 100644
--- a/src/quick/scenegraph/util/qsgareaallocator.cpp
+++ b/src/quick/scenegraph/util/qsgareaallocator.cpp
@@ -42,6 +42,9 @@
#include <QtCore/qglobal.h>
#include <QtCore/qrect.h>
#include <QtCore/qpoint.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qendian.h>
QT_BEGIN_NAMESPACE
@@ -285,4 +288,145 @@ void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node)
} // end while(!done)
}
+namespace {
+ struct AreaAllocatorTable
+ {
+ enum TableSize {
+ HeaderSize = 10,
+ NodeSize = 9
+ };
+
+ enum Offset {
+ // Header
+ majorVersion = 0,
+ minorVersion = 1,
+ width = 2,
+ height = 6,
+
+ // Node
+ split = 0,
+ splitType = 4,
+ flags = 8
+ };
+
+ enum Flags {
+ IsOccupied = 1,
+ HasLeft = 2,
+ HasRight = 4
+ };
+
+ template <typename T>
+ static inline T fetch(const char *data, Offset offset)
+ {
+ return qFromBigEndian<T>(data + int(offset));
+ }
+
+ template <typename T>
+ static inline void put(char *data, Offset offset, T value)
+ {
+ qToBigEndian(value, data + int(offset));
+ }
+ };
+}
+
+QByteArray QSGAreaAllocator::serialize()
+{
+ QVarLengthArray<QSGAreaAllocatorNode *> nodesToProcess;
+
+ QStack<QSGAreaAllocatorNode *> nodes;
+ nodes.push(m_root);
+ while (!nodes.isEmpty()) {
+ QSGAreaAllocatorNode *node = nodes.pop();
+
+ nodesToProcess.append(node);
+ if (node->left != nullptr)
+ nodes.push(node->left);
+ if (node->right != nullptr)
+ nodes.push(node->right);
+ }
+
+ QByteArray ret;
+ ret.resize(AreaAllocatorTable::HeaderSize + AreaAllocatorTable::NodeSize * nodesToProcess.size());
+
+ char *data = ret.data();
+ AreaAllocatorTable::put(data, AreaAllocatorTable::majorVersion, quint8(5));
+ AreaAllocatorTable::put(data, AreaAllocatorTable::minorVersion, quint8(12));
+ AreaAllocatorTable::put(data, AreaAllocatorTable::width, quint32(m_size.width()));
+ AreaAllocatorTable::put(data, AreaAllocatorTable::height, quint32(m_size.height()));
+
+ data += AreaAllocatorTable::HeaderSize;
+ for (QSGAreaAllocatorNode *node : nodesToProcess) {
+ AreaAllocatorTable::put(data, AreaAllocatorTable::split, qint32(node->split));
+ AreaAllocatorTable::put(data, AreaAllocatorTable::splitType, quint32(node->splitType));
+
+ quint8 flags =
+ (node->isOccupied ? AreaAllocatorTable::IsOccupied : 0)
+ | (node->left != nullptr ? AreaAllocatorTable::HasLeft : 0)
+ | (node->right != nullptr ? AreaAllocatorTable::HasRight : 0);
+ AreaAllocatorTable::put(data, AreaAllocatorTable::flags, flags);
+ data += AreaAllocatorTable::NodeSize;
+ }
+
+ return ret;
+}
+
+const char *QSGAreaAllocator::deserialize(const char *data, int size)
+{
+ if (uint(size) < AreaAllocatorTable::HeaderSize) {
+ qWarning("QSGAreaAllocator::deserialize: Data not long enough to fit header");
+ return nullptr;
+ }
+
+ const char *end = data + size;
+
+ quint8 majorVersion = AreaAllocatorTable::fetch<quint8>(data, AreaAllocatorTable::majorVersion);
+ quint8 minorVersion = AreaAllocatorTable::fetch<quint8>(data, AreaAllocatorTable::minorVersion);
+ if (majorVersion != 5 || minorVersion != 12) {
+ qWarning("Unrecognized version %d.%d of QSGAreaAllocator",
+ majorVersion,
+ minorVersion);
+ return nullptr;
+ }
+
+ m_size = QSize(AreaAllocatorTable::fetch<quint32>(data, AreaAllocatorTable::width),
+ AreaAllocatorTable::fetch<quint32>(data, AreaAllocatorTable::height));
+
+ Q_ASSERT(m_root != nullptr);
+ Q_ASSERT(m_root->left == nullptr);
+ Q_ASSERT(m_root->right == nullptr);
+
+ QStack<QSGAreaAllocatorNode *> nodes;
+ nodes.push(m_root);
+
+ data += AreaAllocatorTable::HeaderSize;
+ while (!nodes.isEmpty()) {
+ if (data + AreaAllocatorTable::NodeSize > end) {
+ qWarning("QSGAreaAllocator::deseriable: Data not long enough for nodes");
+ return nullptr;
+ }
+
+ QSGAreaAllocatorNode *node = nodes.pop();
+
+ node->split = AreaAllocatorTable::fetch<qint32>(data, AreaAllocatorTable::split);
+ node->splitType = SplitType(AreaAllocatorTable::fetch<quint32>(data, AreaAllocatorTable::splitType));
+
+ quint8 flags = AreaAllocatorTable::fetch<quint8>(data, AreaAllocatorTable::flags);
+ node->isOccupied = flags & AreaAllocatorTable::IsOccupied;
+
+ if (flags & AreaAllocatorTable::HasLeft) {
+ node->left = new QSGAreaAllocatorNode(node);
+ nodes.push(node->left);
+ }
+
+ if (flags & AreaAllocatorTable::HasRight) {
+ node->right = new QSGAreaAllocatorNode(node);
+ nodes.push(node->right);
+ }
+
+ data += AreaAllocatorTable::NodeSize;
+ }
+
+ return data;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgareaallocator_p.h b/src/quick/scenegraph/util/qsgareaallocator_p.h
index 8bc05a5a5b..300a8128c0 100644
--- a/src/quick/scenegraph/util/qsgareaallocator_p.h
+++ b/src/quick/scenegraph/util/qsgareaallocator_p.h
@@ -69,6 +69,10 @@ public:
bool deallocate(const QRect &rect);
bool isEmpty() const { return m_root == nullptr; }
QSize size() const { return m_size; }
+
+ QByteArray serialize();
+ const char *deserialize(const char *data, int size);
+
private:
bool allocateInNode(const QSize &size, QPoint &result, const QRect &currentRect, QSGAreaAllocatorNode *node);
bool deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node);