diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2018-07-08 11:23:24 +0200 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2018-08-17 11:06:20 +0000 |
commit | 36c6b727c5f433ce3f22e18d93e2502df1c526aa (patch) | |
tree | 4c57debdf593897440d9d012935bfca16ba7cb66 /src/quick/scenegraph/util | |
parent | 9fbdc8c4c2c028427b19907d636a7a83d79cbd09 (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.cpp | 144 | ||||
-rw-r--r-- | src/quick/scenegraph/util/qsgareaallocator_p.h | 4 |
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 ¤tRect, QSGAreaAllocatorNode *node); bool deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node); |