1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsCorePrerequisites.h" |
6 | #include "CoreThread/BsCoreObject.h" |
7 | #include "RenderAPI/BsIndexBuffer.h" |
8 | |
9 | namespace bs |
10 | { |
11 | /** @addtogroup Resources |
12 | * @{ |
13 | */ |
14 | |
15 | /** |
16 | * Mesh heap allows you to quickly allocate and deallocate a large amounts of temporary meshes without the large |
17 | * overhead of normal Mesh creation. Only requirement is that meshes share the same vertex description and index type. |
18 | * |
19 | * @note |
20 | * This class should be considered as a replacement for a normal Mesh if you are constantly updating the mesh (for |
21 | * example every frame) and you are not able to discard entire mesh contents on each update. Not using discard flag on |
22 | * normal meshes may introduce GPU-CPU sync points which may severely limit performance. Primary purpose of this class |
23 | * is to avoid those sync points by not forcing you to discard contents. |
24 | * Downside is that this class may allocate 2-3x (or more) memory than it is actually needed for your data. |
25 | * @note |
26 | * Sim thread only |
27 | */ |
28 | class BS_CORE_EXPORT MeshHeap : public CoreObject |
29 | { |
30 | public: |
31 | /** |
32 | * Allocates a new mesh in the heap, expanding the heap if needed. Mesh will be initialized with the provided |
33 | * @p meshData. You may use the returned transient mesh for drawing. |
34 | * |
35 | * @note |
36 | * Offsets provided by MeshData are ignored. MeshHeap will determine where the data will be written internally. |
37 | */ |
38 | SPtr<TransientMesh> alloc(const SPtr<MeshData>& meshData, DrawOperationType drawOp = DOT_TRIANGLE_LIST); |
39 | |
40 | /** |
41 | * Deallocates the provided mesh and makes that room on the heap re-usable as soon as the GPU is also done with the |
42 | * mesh. |
43 | */ |
44 | void dealloc(const SPtr<TransientMesh>& mesh); |
45 | |
46 | /** Retrieves a core implementation of a mesh heap usable only from the core thread. */ |
47 | SPtr<ct::MeshHeap> getCore() const; |
48 | |
49 | /** |
50 | * Creates a new mesh heap. |
51 | * |
52 | * @param[in] numVertices Initial number of vertices the heap may store. This will grow automatically if needed. |
53 | * @param[in] numIndices Initial number of indices the heap may store. This will grow automatically if needed. |
54 | * @param[in] vertexDesc Description of the stored vertices. |
55 | * @param[in] indexType Type of the stored indices. |
56 | */ |
57 | static SPtr<MeshHeap> create(UINT32 numVertices, UINT32 numIndices, |
58 | const SPtr<VertexDataDesc>& vertexDesc, IndexType indexType = IT_32BIT); |
59 | |
60 | private: |
61 | /** @copydoc create */ |
62 | MeshHeap(UINT32 numVertices, UINT32 numIndices, |
63 | const SPtr<VertexDataDesc>& vertexDesc, IndexType indexType = IT_32BIT); |
64 | |
65 | /** @copydoc CoreObject::createCore */ |
66 | SPtr<ct::CoreObject> createCore() const override; |
67 | |
68 | private: |
69 | UINT32 mNumVertices; |
70 | UINT32 mNumIndices; |
71 | |
72 | SPtr<VertexDataDesc> mVertexDesc; |
73 | IndexType mIndexType; |
74 | |
75 | Map<UINT32, SPtr<TransientMesh>> mMeshes; |
76 | UINT32 mNextFreeId; |
77 | }; |
78 | |
79 | /** @} */ |
80 | |
81 | namespace ct |
82 | { |
83 | /** @addtogroup Resources-Internal |
84 | * @{ |
85 | */ |
86 | |
87 | /** |
88 | * Core thread version of bs::MeshHeap. |
89 | * |
90 | * @note Core thread only. |
91 | */ |
92 | class BS_CORE_EXPORT MeshHeap : public CoreObject |
93 | { |
94 | /** Signifies how is a data chunk used. */ |
95 | enum class UseFlags |
96 | { |
97 | Used, /**< Data chunk is used by both CPU and GPU. */ |
98 | CPUFree, /**< Data chunk was released by CPU but not GPU. */ |
99 | GPUFree, /**< Data chunk was released by GPU but not CPU. */ |
100 | Free /**< Data chunk was released by both CPU and GPU. */ |
101 | }; |
102 | |
103 | /** Represents a continuous chunk of memory. */ |
104 | struct ChunkData |
105 | { |
106 | UINT32 start, size; |
107 | }; |
108 | |
109 | /** Represents an allocated piece of data representing a mesh. */ |
110 | struct AllocatedData |
111 | { |
112 | UINT32 vertChunkIdx; |
113 | UINT32 idxChunkIdx; |
114 | |
115 | UseFlags useFlags; |
116 | UINT32 eventQueryIdx; |
117 | SPtr<TransientMesh> mesh; |
118 | }; |
119 | |
120 | /** Data about a GPU query. */ |
121 | struct QueryData |
122 | { |
123 | SPtr<EventQuery> query; |
124 | UINT32 queryId; |
125 | }; |
126 | |
127 | public: |
128 | ~MeshHeap(); |
129 | |
130 | private: |
131 | friend class bs::MeshHeap; |
132 | friend class bs::TransientMesh; |
133 | friend class TransientMesh; |
134 | |
135 | MeshHeap(UINT32 numVertices, UINT32 numIndices, |
136 | const SPtr<VertexDataDesc>& vertexDesc, IndexType indexType, GpuDeviceFlags deviceMask); |
137 | |
138 | /** @copydoc CoreObject::initialize() */ |
139 | void initialize() override; |
140 | |
141 | /** |
142 | * Allocates a new mesh in the heap, expanding the heap if needed. |
143 | * |
144 | * @param[in] mesh Mesh for which we are allocating the data. |
145 | * @param[in] meshData Data to initialize the new mesh with. |
146 | */ |
147 | void alloc(SPtr<TransientMesh> mesh, const SPtr<MeshData>& meshData); |
148 | |
149 | /** Deallocates the provided mesh. Freed memory will be re-used as soon as the GPU is done with the mesh. */ |
150 | void dealloc(SPtr<TransientMesh> mesh); |
151 | |
152 | /** Resizes the vertex buffers so they max contain the provided number of vertices. */ |
153 | void growVertexBuffer(UINT32 numVertices); |
154 | |
155 | /** Resizes the index buffer so they max contain the provided number of indices. */ |
156 | void growIndexBuffer(UINT32 numIndices); |
157 | |
158 | /** |
159 | * Creates a new event query or returns an existing one from the pool if available. Returned value is an index |
160 | * into event query array. |
161 | */ |
162 | UINT32 createEventQuery(); |
163 | |
164 | /** Frees the event query with the specified index and returns it to the pool so it may be reused later. */ |
165 | void freeEventQuery(UINT32 idx); |
166 | |
167 | /** Gets internal vertex data for all the meshes. */ |
168 | SPtr<VertexData> getVertexData() const; |
169 | |
170 | /** Gets internal index data for all the meshes. */ |
171 | SPtr<IndexBuffer> getIndexBuffer() const; |
172 | |
173 | /** Returns a structure that describes how are the vertices stored in the mesh's vertex buffer. */ |
174 | SPtr<VertexDataDesc> getVertexDesc() const; |
175 | |
176 | /** |
177 | * Returns the offset in vertices from the start of the buffer to the first vertex of the mesh with the provided ID. |
178 | */ |
179 | UINT32 getVertexOffset(UINT32 meshId) const; |
180 | |
181 | /** |
182 | * Returns the offset in indices from the start of the buffer to the first index of the mesh with the provided ID. |
183 | */ |
184 | UINT32 getIndexOffset(UINT32 meshId) const; |
185 | |
186 | /** Called by the render system when a mesh gets queued to the GPU. */ |
187 | void notifyUsedOnGPU(UINT32 meshId); |
188 | |
189 | /** |
190 | * Called by an GPU event query when GPU processes the query. Normally signals the heap that the GPU is done with |
191 | * the mesh. |
192 | */ |
193 | static void queryTriggered(SPtr<MeshHeap> thisPtr, UINT32 meshId, UINT32 queryId); |
194 | |
195 | /** |
196 | * Attempts to reorganize the vertex and index buffer chunks in order to in order to make free memory contigous. |
197 | * |
198 | * @note |
199 | * This will not actually copy any data from index/vertex buffers, and will only modify the chunk descriptors. |
200 | */ |
201 | void mergeWithNearbyChunks(UINT32 chunkVertIdx, UINT32 chunkIdxIdx); |
202 | |
203 | private: |
204 | UINT32 mNumVertices; |
205 | UINT32 mNumIndices; |
206 | |
207 | Vector<UINT8*> mCPUVertexData; |
208 | UINT8* mCPUIndexData; |
209 | |
210 | SPtr<VertexData> mVertexData; |
211 | SPtr<IndexBuffer> mIndexBuffer; |
212 | |
213 | Map<UINT32, AllocatedData> mMeshAllocData; |
214 | |
215 | SPtr<VertexDataDesc> mVertexDesc; |
216 | IndexType mIndexType; |
217 | GpuDeviceFlags mDeviceMask; |
218 | |
219 | Vector<ChunkData> mVertChunks; |
220 | Vector<ChunkData> mIdxChunks; |
221 | |
222 | Stack<UINT32> mEmptyVertChunks; |
223 | Stack<UINT32> mEmptyIdxChunks; |
224 | |
225 | List<UINT32> mFreeVertChunks; |
226 | List<UINT32> mFreeIdxChunks; |
227 | |
228 | Vector<QueryData> mEventQueries; |
229 | Stack<UINT32> mFreeEventQueries; |
230 | |
231 | UINT32 mNextQueryId; |
232 | |
233 | static const float GrowPercent; |
234 | }; |
235 | |
236 | /** @} */ |
237 | } |
238 | } |