// Copyright (C) 2008-2012 NVIDIA Corporation. // Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef QSSGPERFRAMEALLOCATOR_H #define QSSGPERFRAMEALLOCATOR_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include QT_BEGIN_NAMESPACE class QSSGPerFrameAllocator { struct FastAllocator { struct Slab; enum : size_t { ChunkSize = 8192*2, Alignment = sizeof(void *), SlabSize = ChunkSize - sizeof(Slab *), MaxAlloc = ChunkSize/2 // don't go all the way up to SlabSize, or we'd almost always get a big hole }; struct Slab { Slab() = default; Slab(Slab *previous) { previous->next = this; } Slab *next = nullptr; quint8 data[SlabSize]; }; Q_STATIC_ASSERT(sizeof(Slab) == ChunkSize); Q_STATIC_ASSERT(alignof(Slab) == Alignment); Slab *first = nullptr; Slab *current = nullptr; size_t offset = 0; FastAllocator() { first = current = new Slab; } ~FastAllocator() { Slab *s = first; while (s) { Slab *n = s->next; delete s; s = n; } } void *allocate(size_t size) { size = (size + Alignment - 1) & ~(Alignment - 1); Q_ASSERT(size <= SlabSize); Q_ASSERT(!(offset % Alignment)); size_t amountLeftInSlab = SlabSize - offset; if (size > amountLeftInSlab) { if (current->next) current = current->next; else current = new Slab(current); offset = 0; } quint8 *data = current->data + offset; offset += size; return data; } // only reset, so we can re-use the memory void reset() { current = first; offset = 0; } }; struct LargeAllocator { struct Slab { Slab *next = nullptr; }; Slab *current = nullptr; LargeAllocator() {} // Automatically deallocates everything that hasn't already been deallocated. ~LargeAllocator() { deallocateAll(); } void deallocateAll() { while (current) { Slab *n = current->next; ::free(current); current = n; } current = nullptr; } void *allocate(size_t size) { quint8 *mem = reinterpret_cast(::malloc(sizeof(Slab) + size)); Slab *s = reinterpret_cast(mem); s->next = current; current = s; return mem + sizeof(Slab); } }; FastAllocator m_fastAllocator; LargeAllocator m_largeAllocator; public: QSSGPerFrameAllocator() {} inline void *allocate(size_t size) { if (size < FastAllocator::MaxAlloc) return m_fastAllocator.allocate(size); return m_largeAllocator.allocate(size); } void reset() { m_fastAllocator.reset(); m_largeAllocator.deallocateAll(); } }; QT_END_NAMESPACE #endif // QSSGPERFRAMEALLOCATOR_H