| 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 | } |