diff options
author | Gunnar Sletta <gunnar@sletta.org> | 2014-10-22 13:32:27 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar@sletta.org> | 2014-11-02 11:27:55 +0100 |
commit | d252ba67dadba9471160ce2ec277763178fea9db (patch) | |
tree | 8dc235fc6613b22a49a4e94ff2c78d64d05c213c /src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | |
parent | d1b39ca5c9444a8c54edd3aa4548e27458cee718 (diff) |
Use an allocator for QSGBatchRenderer::Node and Element instances.
Cuts down quite a bit on the time spent on the render thread during
the sync phase.
Change-Id: Ide8c4348141c84ed8abd9a869607a022652c2828
Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 142 |
1 files changed, 129 insertions, 13 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 5447d9ea52..29604cf820 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -31,8 +31,8 @@ ** ****************************************************************************/ -#ifndef ULTRARENDERER_H -#define ULTRARENDERER_H +#ifndef QSGBATCHRENDERER_P_H +#define QSGBATCHRENDERER_P_H #include <private/qsgrenderer_p.h> #include <private/qsgnodeupdater_p.h> @@ -40,6 +40,8 @@ #include <private/qsgrendernode_p.h> +#include <QtCore/QBitArray> + QT_BEGIN_NAMESPACE class QOpenGLVertexArrayObject; @@ -59,6 +61,115 @@ class Updater; class Renderer; class ShaderManager; +template <typename Type, int PageSize> class AllocatorPage +{ +public: + // The memory used by this allocator + char data[sizeof(Type) * PageSize]; + + // 'blocks' contains a list of free indices which can be allocated. + // The first available index is found in PageSize - available. + int blocks[PageSize]; + + // 'available' is the number of available instances this page has left to allocate. + int available; + + // This is not strictly needed, but useful for sanity checking and anyway + // pretty small.. + QBitArray allocated; + + AllocatorPage() + : available(PageSize) + , allocated(PageSize) + { + for (int i=0; i<PageSize; ++i) blocks[i] = i; + } + + Type *at(uint index) const + { + return (Type *) &data[index * sizeof(Type)]; + } +}; + +template <typename Type, int PageSize> class Allocator +{ +public: + Allocator() + { + pages.push_back(new AllocatorPage<Type, PageSize>()); + } + + ~Allocator() + { + qDeleteAll(pages); + } + + Type *allocate() + { + AllocatorPage<Type, PageSize> *p = 0; + for (int i=0; i<pages.size(); ++i) { + if (pages.at(i)->available > 0) { + p = pages.at(i); + break; + } + } + if (!p) { + p = new AllocatorPage<Type, PageSize>(); + pages.push_back(p); + } + uint pos = p->blocks[PageSize - p->available]; + void *mem = p->at(pos); + p->available--; + p->allocated.setBit(pos); + Type *t = new (mem) Type(); + return t; + } + + void releaseExplicit(uint pageIndex, uint index) + { + AllocatorPage<Type, PageSize> *page = pages.at(pageIndex); + if (!page->allocated.testBit(index)) + qFatal("Double delete in allocator: page=%d, index=%d", pageIndex , index); + + // Call the destructor + page->at(index)->~Type(); + + page->allocated[index] = false; + page->available++; + page->blocks[PageSize - page->available] = index; + + // Remove the pages if they are empty and they are the last ones. We need to keep the + // order of pages since we have references to their index, so we can only remove + // from the end. + while (page->available == PageSize && pages.size() > 1 && pages.back() == page) { + pages.pop_back(); + delete page; + page = pages.back(); + } + } + + void release(Type *t) + { + int pageIndex = -1; + for (int i=0; i<pages.size(); ++i) { + AllocatorPage<Type, PageSize> *p = pages.at(i); + if ((Type *) (&p->data[0]) <= t && (Type *) (&p->data[PageSize * sizeof(Type)]) > t) { + pageIndex = i; + break; + } + } + Q_ASSERT(pageIndex >= 0); + + AllocatorPage<Type, PageSize> *page = pages.at(pageIndex); + int index = (quint64(t) - quint64(&page->data[0])) / sizeof(Type); + + releaseExplicit(pageIndex, index); + } + + QVector<AllocatorPage<Type, PageSize> *> pages; +}; + + inline bool hasMaterialWithBlending(QSGGeometryNode *n) { return (n->opaqueMaterial() ? n->opaqueMaterial()->flags() & QSGMaterial::Blending @@ -149,8 +260,8 @@ struct Buffer { struct Element { - Element(QSGGeometryNode *n) - : node(n) + Element() + : node(0) , batch(0) , nextInBatch(0) , root(0) @@ -161,10 +272,15 @@ struct Element { , removed(false) , orphaned(false) , isRenderNode(false) - , isMaterialBlended(n ? hasMaterialWithBlending(n) : false) + , isMaterialBlended(false) { } + void setNode(QSGGeometryNode *n) { + node = n; + isMaterialBlended = hasMaterialWithBlending(n); + } + inline void ensureBoundsValid() { if (!boundsComputed) computeBounds(); @@ -192,8 +308,7 @@ struct Element { struct RenderNodeElement : public Element { RenderNodeElement(QSGRenderNode *rn) - : Element(0) - , renderNode(rn) + : renderNode(rn) { isRenderNode = true; } @@ -289,15 +404,14 @@ struct Batch struct Node { - Node(QSGNode *node, Node *sparent = 0) - : sgNode(node) - , parent(sparent) + Node() + : sgNode(0) + , parent(0) , data(0) , dirtyState(0) , isOpaque(false) , isBatchRoot(false) { - } QSGNode *sgNode; @@ -435,7 +549,6 @@ private: friend class Updater; - void map(Buffer *buffer, int size); void unmap(Buffer *buffer, bool isIndexBuf = false); @@ -532,6 +645,9 @@ private: QHash<Node *, uint> m_visualizeChanceSet; VisualizeMode m_visualizeMode; + + Allocator<Node, 256> m_nodeAllocator; + Allocator<Element, 64> m_elementAllocator; }; Batch *Renderer::newBatch() @@ -556,4 +672,4 @@ Batch *Renderer::newBatch() QT_END_NAMESPACE -#endif // ULTRARENDERER_H +#endif // QSGBATCHRENDERER_P_H |