1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2008-2012 NVIDIA Corporation. 4 ** Copyright (C) 2019 The Qt Company Ltd. 5 ** Contact: https://www.qt.io/licensing/ 6 ** 7 ** This file is part of Qt Quick 3D. 8 ** 9 ** $QT_BEGIN_LICENSE:GPL$ 10 ** Commercial License Usage 11 ** Licensees holding valid commercial Qt licenses may use this file in 12 ** accordance with the commercial license agreement provided with the 13 ** Software or, alternatively, in accordance with the terms contained in 14 ** a written agreement between you and The Qt Company. For licensing terms 15 ** and conditions see https://www.qt.io/terms-conditions. For further 16 ** information use the contact form at https://www.qt.io/contact-us. 17 ** 18 ** GNU General Public License Usage 19 ** Alternatively, this file may be used under the terms of the GNU 20 ** General Public License version 3 or (at your option) any later version 21 ** approved by the KDE Free Qt Foundation. The licenses are as published by 22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3 23 ** included in the packaging of this file. Please review the following 24 ** information to ensure the GNU General Public License requirements will 25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 26 ** 27 ** $QT_END_LICENSE$ 28 ** 29 ****************************************************************************/ 30 31 32 #ifndef QSSGPERFRAMEALLOCATOR_H 33 #define QSSGPERFRAMEALLOCATOR_H 34 35 // 36 // W A R N I N G 37 // ------------- 38 // 39 // This file is not part of the Qt API. It exists purely as an 40 // implementation detail. This header file may change from version to 41 // version without notice, or even be removed. 42 // 43 // We mean it. 44 // 45 46 #include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderglobal_p.h> 47 48 QT_BEGIN_NAMESPACE 49 50 class QSSGPerFrameAllocator 51 { 52 struct FastAllocator 53 { 54 struct Slab; 55 56 enum : size_t { 57 ChunkSize = 8192*2, 58 Alignment = 4, 59 SlabSize = ChunkSize - sizeof(Slab *), 60 MaxAlloc = ChunkSize/2 // don't go all the way up to SlabSize, or we'd almost always get a big hole 61 }; 62 struct Slab { 63 Slab() = default; SlabFastAllocator::Slab64 Slab(Slab *previous) 65 { 66 previous->next = this; 67 } 68 Slab *next = nullptr; 69 quint8 data[SlabSize]; 70 }; 71 Q_STATIC_ASSERT(sizeof(Slab) == ChunkSize); 72 73 Slab *first = nullptr; 74 Slab *current = nullptr; 75 size_t offset = 0; 76 FastAllocatorFastAllocator77 FastAllocator() 78 { 79 first = current = new Slab; 80 } 81 ~FastAllocatorFastAllocator82 ~FastAllocator() 83 { 84 Slab *s = first; 85 while (s) { 86 Slab *n = s->next; 87 delete s; 88 s = n; 89 } 90 } allocateFastAllocator91 void *allocate(size_t size) 92 { 93 size = (size + Alignment - 1) & ~(Alignment - 1); 94 Q_ASSERT(size <= SlabSize); 95 Q_ASSERT(!(offset % Alignment)); 96 97 size_t amountLeftInSlab = SlabSize - offset; 98 if (size > amountLeftInSlab) { 99 if (current->next) 100 current = current->next; 101 else 102 current = new Slab(current); 103 offset = 0; 104 } 105 106 quint8 *data = current->data + offset; 107 offset += size; 108 return data; 109 } 110 111 // only reset, so we can re-use the memory resetFastAllocator112 void reset() { current = first; offset = 0; } 113 }; 114 115 struct LargeAllocator 116 { 117 struct Slab { 118 Slab *next = nullptr; 119 }; 120 Slab *current = nullptr; 121 LargeAllocatorLargeAllocator122 LargeAllocator() {} 123 124 // Automatically deallocates everything that hasn't already been deallocated. ~LargeAllocatorLargeAllocator125 ~LargeAllocator() { deallocateAll(); } 126 deallocateAllLargeAllocator127 void deallocateAll() 128 { 129 while (current) { 130 Slab *n = current->next; 131 ::free(current); 132 current = n; 133 } 134 current = nullptr; 135 } 136 allocateLargeAllocator137 void *allocate(size_t size) 138 { 139 quint8 *mem = reinterpret_cast<quint8 *>(::malloc(sizeof(Slab) + size)); 140 Slab *s = reinterpret_cast<Slab *>(mem); 141 s->next = current; 142 current = s; 143 return mem + sizeof(Slab); 144 } 145 }; 146 147 FastAllocator m_fastAllocator; 148 LargeAllocator m_largeAllocator; 149 150 public: QSSGPerFrameAllocator()151 QSSGPerFrameAllocator() {} 152 allocate(size_t size)153 inline void *allocate(size_t size) 154 { 155 if (size < FastAllocator::MaxAlloc) 156 return m_fastAllocator.allocate(size); 157 158 return m_largeAllocator.allocate(size); 159 } 160 reset()161 void reset() 162 { 163 m_fastAllocator.reset(); 164 m_largeAllocator.deallocateAll(); 165 } 166 }; 167 168 QT_END_NAMESPACE 169 170 #endif // QSSGPERFRAMEALLOCATOR_H 171