//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// #pragma once #include "BsCorePrerequisites.h" #include "BsCoreObject.h" #include "BsDrawOps.h" #include "BsIndexBuffer.h" namespace BansheeEngine { /** @addtogroup Resources-Internal * @{ */ /** * Core thread version of MeshHeap. * * @note Core thread only. */ class BS_CORE_EXPORT MeshHeapCore : public CoreObjectCore { /** Signifies how is a data chunk used. */ enum class UseFlags { Used, /**< Data chunk is used by both CPU and GPU. */ CPUFree, /**< Data chunk was released by CPU but not GPU. */ GPUFree, /**< Data chunk was released by GPU but not CPU. */ Free /**< Data chunk was released by both CPU and GPU. */ }; /** Represents a continuous chunk of memory. */ struct ChunkData { UINT32 start, size; }; /** Represents an allocated piece of data representing a mesh. */ struct AllocatedData { UINT32 vertChunkIdx; UINT32 idxChunkIdx; UseFlags useFlags; UINT32 eventQueryIdx; SPtr mesh; }; /** Data about a GPU query. */ struct QueryData { SPtr query; UINT32 queryId; }; public: ~MeshHeapCore(); private: friend class MeshHeap; friend class TransientMesh; friend class TransientMeshCore; MeshHeapCore(UINT32 numVertices, UINT32 numIndices, const SPtr& vertexDesc, IndexType indexType = IT_32BIT); /** @copydoc CoreObjectCore::initialize() */ virtual void initialize() override; /** * Allocates a new mesh in the heap, expanding the heap if needed. * * @param[in] meshId Mesh for which we are allocating the data. * @param[in] meshData Data to initialize the new mesh with. */ void alloc(SPtr mesh, const SPtr& meshData); /** Deallocates the provided mesh. Freed memory will be re-used as soon as the GPU is done with the mesh. */ void dealloc(SPtr mesh); /** Resizes the vertex buffers so they max contain the provided number of vertices. */ void growVertexBuffer(UINT32 numVertices); /** Resizes the index buffer so they max contain the provided number of indices. */ void growIndexBuffer(UINT32 numIndices); /** * Creates a new event query or returns an existing one from the pool if available. Returned value is an index * into event query array. */ UINT32 createEventQuery(); /** Frees the event query with the specified index and returns it to the pool so it may be reused later. */ void freeEventQuery(UINT32 idx); /** Gets internal vertex data for all the meshes. */ SPtr getVertexData() const; /** Gets internal index data for all the meshes. */ SPtr getIndexBuffer() const; /** Returns a structure that describes how are the vertices stored in the mesh's vertex buffer. */ SPtr getVertexDesc() const; /** * Returns the offset in vertices from the start of the buffer to the first vertex of the mesh with the provided ID. */ UINT32 getVertexOffset(UINT32 meshId) const; /** * Returns the offset in indices from the start of the buffer to the first index of the mesh with the provided ID. */ UINT32 getIndexOffset(UINT32 meshId) const; /** Called by the render system when a mesh gets queued to the GPU. */ void notifyUsedOnGPU(UINT32 meshId); /** * Called by an GPU event query when GPU processes the query. Normally signals the heap that the GPU is done with * the mesh. */ static void queryTriggered(SPtr thisPtr, UINT32 meshId, UINT32 queryId); /** * Attempts to reorganize the vertex and index buffer chunks in order to in order to make free memory contigous. * * @note * This will not actually copy any data from index/vertex buffers, and will only modify the chunk descriptors. */ void mergeWithNearbyChunks(UINT32 chunkVertIdx, UINT32 chunkIdxIdx); private: UINT32 mNumVertices; UINT32 mNumIndices; Vector mCPUVertexData; UINT8* mCPUIndexData; SPtr mVertexData; SPtr mIndexBuffer; Map mMeshAllocData; SPtr mVertexDesc; IndexType mIndexType; Vector mVertChunks; Vector mIdxChunks; Stack mEmptyVertChunks; Stack mEmptyIdxChunks; List mFreeVertChunks; List mFreeIdxChunks; Vector mEventQueries; Stack mFreeEventQueries; UINT32 mNextQueryId; static const float GrowPercent; }; /** @} */ /** @addtogroup Resources * @{ */ /** * Mesh heap allows you to quickly allocate and deallocate a large amounts of temporary meshes without the large * overhead of normal Mesh creation. Only requirement is that meshes share the same vertex description and index type. * * @note * This class should be considered as a replacement for a normal Mesh if you are constantly updating the mesh (for * example every frame) and you are not able to discard entire mesh contents on each update. Not using discard flag on * normal meshes may introduce GPU-CPU sync points which may severely limit performance. Primary purpose of this class * is to avoid those sync points by not forcing you to discard contents. * Downside is that this class may allocate 2-3x (or more) memory than it is actually needed for your data. * @note * Sim thread only */ class BS_CORE_EXPORT MeshHeap : public CoreObject { public: /** * Allocates a new mesh in the heap, expanding the heap if needed. Mesh will be initialized with the provided * @p meshData. You may use the returned transient mesh for drawing. * * @note * Offsets provided by MeshData are ignored. MeshHeap will determine where the data will be written internally. */ SPtr alloc(const SPtr& meshData, DrawOperationType drawOp = DOT_TRIANGLE_LIST); /** * Deallocates the provided mesh and makes that room on the heap re-usable as soon as the GPU is also done with the * mesh. */ void dealloc(const SPtr& mesh); /** Retrieves a core implementation of a mesh heap usable only from the core thread. */ SPtr getCore() const; /** * Creates a new mesh heap. * * @param[in] numVertices Initial number of vertices the heap may store. This will grow automatically if needed. * @param[in] numIndices Initial number of indices the heap may store. This will grow automatically if needed. * @param[in] vertexDesc Description of the stored vertices. * @param[in] indexType Type of the stored indices. */ static SPtr create(UINT32 numVertices, UINT32 numIndices, const SPtr& vertexDesc, IndexType indexType = IT_32BIT); private: /** @copydoc create */ MeshHeap(UINT32 numVertices, UINT32 numIndices, const SPtr& vertexDesc, IndexType indexType = IT_32BIT); /** @copydoc CoreObject::createCore */ SPtr createCore() const override; private: UINT32 mNumVertices; UINT32 mNumIndices; SPtr mVertexDesc; IndexType mIndexType; Map> mMeshes; UINT32 mNextFreeId; }; /** @} */ }