1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5
6#ifndef QSSGPERFRAMEALLOCATOR_H
7#define QSSGPERFRAMEALLOCATOR_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderglobal_p.h>
21
22QT_BEGIN_NAMESPACE
23
24class QSSGPerFrameAllocator
25{
26 struct FastAllocator
27 {
28 struct Slab;
29
30 enum : size_t {
31 ChunkSize = 8192*2,
32 Alignment = sizeof(void *),
33 SlabSize = ChunkSize - sizeof(Slab *),
34 MaxAlloc = ChunkSize/2 // don't go all the way up to SlabSize, or we'd almost always get a big hole
35 };
36 struct Slab {
37 Slab() = default;
38 Slab(Slab *previous)
39 {
40 previous->next = this;
41 }
42 Slab *next = nullptr;
43 quint8 data[SlabSize];
44 };
45 Q_STATIC_ASSERT(sizeof(Slab) == ChunkSize);
46 Q_STATIC_ASSERT(alignof(Slab) == Alignment);
47
48 Slab *first = nullptr;
49 Slab *current = nullptr;
50 size_t offset = 0;
51
52 FastAllocator()
53 {
54 first = current = new Slab;
55 }
56
57 ~FastAllocator()
58 {
59 Slab *s = first;
60 while (s) {
61 Slab *n = s->next;
62 delete s;
63 s = n;
64 }
65 }
66 void *allocate(size_t size)
67 {
68 size = (size + Alignment - 1) & ~(Alignment - 1);
69 Q_ASSERT(size <= SlabSize);
70 Q_ASSERT(!(offset % Alignment));
71
72 size_t amountLeftInSlab = SlabSize - offset;
73 if (size > amountLeftInSlab) {
74 if (current->next)
75 current = current->next;
76 else
77 current = new Slab(current);
78 offset = 0;
79 }
80
81 quint8 *data = current->data + offset;
82 offset += size;
83 return data;
84 }
85
86 // only reset, so we can re-use the memory
87 void reset() { current = first; offset = 0; }
88 };
89
90 struct LargeAllocator
91 {
92 struct Slab {
93 Slab *next = nullptr;
94 };
95 Slab *current = nullptr;
96
97 LargeAllocator() {}
98
99 // Automatically deallocates everything that hasn't already been deallocated.
100 ~LargeAllocator() { deallocateAll(); }
101
102 void deallocateAll()
103 {
104 while (current) {
105 Slab *n = current->next;
106 ::free(ptr: current);
107 current = n;
108 }
109 current = nullptr;
110 }
111
112 void *allocate(size_t size)
113 {
114 quint8 *mem = reinterpret_cast<quint8 *>(::malloc(size: sizeof(Slab) + size));
115 Slab *s = reinterpret_cast<Slab *>(mem);
116 s->next = current;
117 current = s;
118 return mem + sizeof(Slab);
119 }
120 };
121
122 FastAllocator m_fastAllocator;
123 LargeAllocator m_largeAllocator;
124
125public:
126 QSSGPerFrameAllocator() {}
127
128 inline void *allocate(size_t size)
129 {
130 if (size < FastAllocator::MaxAlloc)
131 return m_fastAllocator.allocate(size);
132
133 return m_largeAllocator.allocate(size);
134 }
135
136 void reset()
137 {
138 m_fastAllocator.reset();
139 m_largeAllocator.deallocateAll();
140 }
141};
142
143QT_END_NAMESPACE
144
145#endif // QSSGPERFRAMEALLOCATOR_H
146

source code of qtquick3d/src/runtimerender/qssgperframeallocator_p.h