diff options
-rw-r--r-- | src/quick/scenegraph/qsgadaptationlayer.cpp | 15 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgadaptationlayer_p.h | 9 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp | 295 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h | 4 | ||||
-rw-r--r-- | src/quick/scenegraph/util/qsgareaallocator.cpp | 144 | ||||
-rw-r--r-- | src/quick/scenegraph/util/qsgareaallocator_p.h | 4 |
6 files changed, 458 insertions, 13 deletions
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 46af0f28f0..c99e149aa5 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -82,19 +82,26 @@ QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache() { } +QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::emptyData(glyph_t glyph) +{ + GlyphData gd; + gd.texture = &s_emptyTexture; + QHash<glyph_t, GlyphData>::iterator it = m_glyphsData.insert(glyph, gd); + return it.value(); +} + QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph) { QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph); if (data == m_glyphsData.end()) { - GlyphData gd; - gd.texture = &s_emptyTexture; + GlyphData &gd = emptyData(glyph); gd.path = m_referenceFont.pathForGlyph(glyph); // need bounding rect in base font size scale qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution); QTransform scaleDown; scaleDown.scale(scaleFactor, scaleFactor); gd.boundingRect = scaleDown.mapRect(gd.path.boundingRect()); - data = m_glyphsData.insert(glyph, gd); + return gd; } return data.value(); } diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 5a465831cb..ba5c4353b2 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -83,6 +83,7 @@ class QSGGlyphNode; class QSGRootNode; class QSGSpriteNode; class QSGRenderNode; +class QSGRenderContext; class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx { @@ -507,6 +508,7 @@ protected: uint textureIdForGlyph(glyph_t glyph) const; GlyphData &glyphData(glyph_t glyph); + GlyphData &emptyData(glyph_t glyph); #if defined(QSG_DISTANCEFIELD_CACHE_DEBUG) void saveTexture(GLuint textureId, int width, int height) const; @@ -514,11 +516,14 @@ protected: inline bool isCoreProfile() const { return m_coreProfile; } -private: + bool m_doubleGlyphResolution; + +protected: QRawFont m_referenceFont; + +private: int m_glyphCount; - bool m_doubleGlyphResolution; bool m_coreProfile; QList<Texture> m_textures; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index ef189ba461..ccc57b0b86 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -39,12 +39,18 @@ #include "qsgdefaultdistancefieldglyphcache_p.h" +#include <QtCore/qelapsedtimer.h> +#include <QtCore/qbuffer.h> +#include <QtQml/qqmlfile.h> + #include <QtGui/private/qdistancefield_p.h> #include <QtGui/private/qopenglcontext_p.h> #include <QtQml/private/qqmlglobal_p.h> #include <qopenglfunctions.h> #include <qopenglframebufferobject.h> #include <qmath.h> +#include "qsgcontext_p.h" + #if !defined(QT_OPENGL_ES_2) #include <QtGui/qopenglfunctions_3_2_core.h> @@ -59,10 +65,12 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI # define QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING 2 #endif -QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font) +QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, + const QRawFont &font) : QSGDistanceFieldGlyphCache(c, font) , m_maxTextureSize(0) , m_maxTextureCount(3) + , m_areaAllocator(nullptr) , m_blitProgram(nullptr) , m_blitBuffer(QOpenGLBuffer::VertexBuffer) , m_fboGuard(nullptr) @@ -81,7 +89,8 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLCont qWarning("Buffer creation failed"); } - m_areaAllocator = new QSGAreaAllocator(QSize(maxTextureSize(), m_maxTextureCount * maxTextureSize())); + // Load a pregenerated cache if the font contains one + loadPregeneratedCache(font); } QSGDefaultDistanceFieldGlyphCache::~QSGDefaultDistanceFieldGlyphCache() @@ -101,6 +110,9 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph QList<GlyphPosition> glyphPositions; QVector<glyph_t> glyphsToRender; + if (m_areaAllocator == nullptr) + m_areaAllocator = new QSGAreaAllocator(QSize(maxTextureSize(), m_maxTextureCount * maxTextureSize())); + for (QSet<glyph_t>::const_iterator it = glyphs.constBegin(); it != glyphs.constEnd() ; ++it) { glyph_t glyphIndex = *it; @@ -237,10 +249,23 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph m_unusedGlyphs += glyphs; } -void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height) +void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, + int width, + int height) +{ + QByteArray zeroBuf(width * height, 0); + createTexture(texInfo, width, height, zeroBuf.constData()); +} + +void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, + int width, + int height, + const void *pixels) { - if (useTextureResizeWorkaround() && texInfo->image.isNull()) + if (useTextureResizeWorkaround() && texInfo->image.isNull()) { texInfo->image = QDistanceField(width, height); + memcpy(texInfo->image.bits(), pixels, width * height); + } while (m_funcs->glGetError() != GL_NO_ERROR) { } @@ -261,8 +286,7 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int const GLenum format = GL_ALPHA; #endif - QByteArray zeroBuf(width * height, 0); - m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, zeroBuf.constData()); + m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, pixels); texInfo->size = QSize(width, height); @@ -520,4 +544,261 @@ int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const return m_maxTextureSize; } +namespace { + struct Qtdf { + // We need these structs to be tightly packed, but some compilers we use do not + // support #pragma pack(1), so we need to hardcode the offsets/sizes in the + // file format + enum TableSize { + HeaderSize = 14, + GlyphRecordSize = 46, + TextureRecordSize = 17 + }; + + enum Offset { + // Header + majorVersion = 0, + minorVersion = 1, + pixelSize = 2, + textureSize = 4, + flags = 8, + headerPadding = 9, + numGlyphs = 10, + + // Glyph record + glyphIndex = 0, + textureOffsetX = 4, + textureOffsetY = 8, + textureWidth = 12, + textureHeight = 16, + xMargin = 20, + yMargin = 24, + boundingRectX = 28, + boundingRectY = 32, + boundingRectWidth = 36, + boundingRectHeight = 40, + textureIndex = 44, + + // Texture record + allocatedX = 0, + allocatedY = 4, + allocatedWidth = 8, + allocatedHeight = 12, + texturePadding = 16 + + }; + + template <typename T> + static inline T fetch(const char *data, Offset offset) + { + return qFromBigEndian<T>(data + int(offset)); + } + }; +} + +bool QSGDefaultDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font) +{ + // The pregenerated data must be loaded first, otherwise the area allocator + // will be wrong + if (m_areaAllocator != nullptr) { + qWarning("Font cache must be loaded before cache is used"); + return false; + } + + static QElapsedTimer timer; + + bool profile = QSG_LOG_TIME_GLYPH().isDebugEnabled(); + if (profile) + timer.start(); + + QByteArray qtdfTable = font.fontTable("qtdf"); + if (qtdfTable.isEmpty()) + return false; + + typedef QHash<TextureInfo *, QVector<glyph_t> > GlyphTextureHash; + + GlyphTextureHash glyphTextures; + + if (uint(qtdfTable.size()) < Qtdf::HeaderSize) { + qWarning("Invalid qtdf table in font '%s'", + qPrintable(font.familyName())); + return false; + } + + const char *qtdfTableStart = qtdfTable.constData(); + const char *qtdfTableEnd = qtdfTableStart + qtdfTable.size(); + + int padding = 0; + int textureCount = 0; + { + quint8 majorVersion = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::majorVersion); + quint8 minorVersion = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::minorVersion); + if (majorVersion != 5 || minorVersion != 12) { + qWarning("Invalid version of qtdf table %d.%d in font '%s'", + majorVersion, + minorVersion, + qPrintable(font.familyName())); + return false; + } + + qreal pixelSize = qreal(Qtdf::fetch<quint16>(qtdfTableStart, Qtdf::pixelSize)); + m_maxTextureSize = Qtdf::fetch<quint32>(qtdfTableStart, Qtdf::textureSize); + m_doubleGlyphResolution = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::flags) == 1; + padding = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::headerPadding); + + if (pixelSize <= 0.0) { + qWarning("Invalid pixel size in '%s'", qPrintable(font.familyName())); + return false; + } + + if (m_maxTextureSize <= 0) { + qWarning("Invalid texture size in '%s'", qPrintable(font.familyName())); + return false; + } + + int systemMaxTextureSize; + m_funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &systemMaxTextureSize); + + if (m_maxTextureSize > systemMaxTextureSize) { + qWarning("System maximum texture size is %d. This is lower than the value in '%s', which is %d", + systemMaxTextureSize, + qPrintable(font.familyName()), + m_maxTextureSize); + } + + if (padding != QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING) { + qWarning("Padding mismatch in '%s'. Font requires %d, but Qt is compiled with %d.", + qPrintable(font.familyName()), + padding, + QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING); + } + + m_referenceFont.setPixelSize(pixelSize); + + quint32 glyphCount = Qtdf::fetch<quint32>(qtdfTableStart, Qtdf::numGlyphs); + m_unusedGlyphs.reserve(glyphCount); + + const char *allocatorData = qtdfTableStart + Qtdf::HeaderSize; + { + m_areaAllocator = new QSGAreaAllocator(QSize(0, 0)); + allocatorData = m_areaAllocator->deserialize(allocatorData, qtdfTableEnd - allocatorData); + if (allocatorData == nullptr) + return false; + } + + if (m_areaAllocator->size().height() % m_maxTextureSize != 0) { + qWarning("Area allocator size mismatch in '%s'", qPrintable(font.familyName())); + return false; + } + + textureCount = m_areaAllocator->size().height() / m_maxTextureSize; + m_maxTextureCount = qMax(m_maxTextureCount, textureCount); + + const char *textureRecord = allocatorData; + for (int i = 0; i < textureCount; ++i, textureRecord += Qtdf::TextureRecordSize) { + if (textureRecord + Qtdf::TextureRecordSize > qtdfTableEnd) { + qWarning("qtdf table too small in font '%s'.", + qPrintable(font.familyName())); + return false; + } + + TextureInfo *tex = textureInfo(i); + tex->allocatedArea.setX(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedX)); + tex->allocatedArea.setY(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedY)); + tex->allocatedArea.setWidth(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedWidth)); + tex->allocatedArea.setHeight(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedHeight)); + tex->padding = Qtdf::fetch<quint8>(textureRecord, Qtdf::texturePadding); + } + + const char *glyphRecord = textureRecord; + for (quint32 i = 0; i < glyphCount; ++i, glyphRecord += Qtdf::GlyphRecordSize) { + if (glyphRecord + Qtdf::GlyphRecordSize > qtdfTableEnd) { + qWarning("qtdf table too small in font '%s'.", + qPrintable(font.familyName())); + return false; + } + + glyph_t glyph = Qtdf::fetch<quint32>(glyphRecord, Qtdf::glyphIndex); + m_unusedGlyphs.insert(glyph); + + GlyphData &glyphData = emptyData(glyph); + +#define FROM_FIXED_POINT(value) \ +(((qreal)value)/(qreal)65536) + + glyphData.texCoord.x = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::textureOffsetX)); + glyphData.texCoord.y = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::textureOffsetY)); + glyphData.texCoord.width = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::textureWidth)); + glyphData.texCoord.height = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::textureHeight)); + glyphData.texCoord.xMargin = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::xMargin)); + glyphData.texCoord.yMargin = FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::yMargin)); + glyphData.boundingRect.setX(FROM_FIXED_POINT(Qtdf::fetch<qint32>(glyphRecord, Qtdf::boundingRectX))); + glyphData.boundingRect.setY(FROM_FIXED_POINT(Qtdf::fetch<qint32>(glyphRecord, Qtdf::boundingRectY))); + glyphData.boundingRect.setWidth(FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::boundingRectWidth))); + glyphData.boundingRect.setHeight(FROM_FIXED_POINT(Qtdf::fetch<quint32>(glyphRecord, Qtdf::boundingRectHeight))); + +#undef FROM_FIXED_POINT + + int textureIndex = Qtdf::fetch<quint16>(glyphRecord, Qtdf::textureIndex); + if (textureIndex < 0 || textureIndex >= textureCount) { + qWarning("Invalid texture index %d (texture count == %d) in '%s'", + textureIndex, + textureCount, + qPrintable(font.familyName())); + return false; + } + + + TextureInfo *texInfo = textureInfo(textureIndex); + m_glyphsTexture.insert(glyph, texInfo); + + glyphTextures[texInfo].append(glyph); + } + + GLint alignment = 4; // default value + m_funcs->glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + + m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + const uchar *textureData = reinterpret_cast<const uchar *>(glyphRecord); + for (int i = 0; i < textureCount; ++i) { + + TextureInfo *texInfo = textureInfo(i); + + int width = texInfo->allocatedArea.width(); + int height = texInfo->allocatedArea.height(); + qint64 size = width * height; + if (reinterpret_cast<const char *>(textureData + size) > qtdfTableEnd) { + qWarning("qtdf table too small in font '%s'.", + qPrintable(font.familyName())); + return false; + } + + createTexture(texInfo, width, height, textureData); + + QVector<glyph_t> glyphs = glyphTextures.value(texInfo); + + Texture t; + t.textureId = texInfo->texture; + t.size = texInfo->size; + + setGlyphsTexture(glyphs, t); + + textureData += size; + } + + m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); + } + + if (profile) { + quint64 now = timer.elapsed(); + qCDebug(QSG_LOG_TIME_GLYPH, + "distancefield: %d pre-generated glyphs loaded in %dms", + m_unusedGlyphs.size(), + (int) now); + } + + return true; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index 76c0d20647..a0e4387af9 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -85,7 +85,10 @@ public: void setMaxTextureCount(int max) { m_maxTextureCount = max; } int maxTextureCount() const { return m_maxTextureCount; } + private: + bool loadPregeneratedCache(const QRawFont &font); + struct TextureInfo { GLuint texture; QSize size; @@ -96,6 +99,7 @@ private: TextureInfo(const QRect &preallocRect = QRect()) : texture(0), allocatedArea(preallocRect) { } }; + void createTexture(TextureInfo * texInfo, int width, int height, const void *pixels); void createTexture(TextureInfo * texInfo, int width, int height); void resizeTexture(TextureInfo * texInfo, int width, int height); 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); |