/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #ifndef CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H #define CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H #pragma once // The type of pool responsible for temporary allocations within the 3dengine // // Note: The header is included here for reasons of devirtualization. If // included directly from the precompiled header in 3dEngine, the gamedll will // fail to compile! #include #include using NCryPoolAlloc::CFirstFit; // speed of allocations are crucial, so simply use the first fitting free allocation using NCryPoolAlloc::CInPlace; // using NCryPoolAlloc::CMemoryDynamic; // the pool itself will be dynamically allocated using NCryPoolAlloc::CListItemInPlace; // use inplace items // Tempororary Pool Holder class CTemporaryPool { private: // Access granted for 3dEngine to create, destroy and maintain the temporary // pool for the 3d engine friend class C3DEngine; // The static pool instance - one pool to rule them all (temp allocations at least) static CTemporaryPool* s_Instance; // The type of the backing temporary pool typedef CFirstFit, CListItemInPlace> TTemporaryPool; TTemporaryPool Pool; // A non-recursive critical section guards the pool against concurrent access typedef CryCriticalSectionNonRecursive TTemporaryPoolLock; TTemporaryPoolLock Lock; // Initialize the pool manager. // // Allocates the backing storage and initializes the temporary pool // itself. The backing storage is aligned to 16 bytes to reduce the amount of // cachelines crossed by the temporary pool static bool Initialize(size_t poolSize) { // Create the object instance s_Instance = new CTemporaryPool(); if (!s_Instance) { CryFatalError("CTemporaryPool::Init(): could not create an instance of CTemporaryPool"); return false; } // Allocate the backing storage uint8* tempPool = reinterpret_cast(CryModuleMemalign(poolSize, 16)); if (!tempPool) { CryFatalError("CTemporaryPool::Init(): could not allocate %" PRISIZE_T " bytes for temportary pool", poolSize); return false; } // Initialize the actual pool s_Instance->Pool.InitMem(poolSize, tempPool); return true; } // Shutdown the temporary pool manager. // // Frees the temporary pool static bool Shutdown() { if (s_Instance == NULL) { CryFatalError("CTemporaryPool::Shutdown(): no temporary pool instance present"); return false; } bool error = false; CTemporaryPool& instance = *s_Instance; if (instance.Pool.Data()) { CryModuleMemalignFree(instance.Pool.Data()); } else { error = true; } delete s_Instance; s_Instance = NULL; return !error; } // Templated construct helper member function using an inplace factory // // Called from the templated New function below. Returns a typed // pointer to the inplace constructed object. template T* Construct(const InPlaceFactory& factory, void* storage) { return reinterpret_cast(factory.template apply(storage)); } // Templated destruct helper member function. // // Calls the object's destructor and returns a void pointer to the storage template void* Destruct(T* obj) { obj->~T(); return reinterpret_cast(obj); } // Empty private constructor/destructors to prevent clients from creating and // destroying instances of CTemporaryPool (there should only be one instance // in the 3DEngine). CTemporaryPool() {}; ~CTemporaryPool() {}; public: // Allocate a block of memory with the given size and alignment void* Allocate(size_t size, size_t align) { AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock); void* pData = Pool.Allocate(size, align); if (pData == NULL) { CryFatalError("**** could not allocate %" PRISIZE_T " bytes from temporary pool", size); } return Pool.Resolve(pData); }; // Allocates memory and constructs object of type 'T' // // Note: This method is respects the alignment of 'T' via C99 alignof() template T* New(const Expr& expr) { AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock); void* pObjStorage = Pool.Allocate(sizeof(T), alignof(T)); if (pObjStorage == NULL) { CryFatalError("**** could not allocate %d bytes from temporary pool", (int)sizeof (T)); } return Construct(expr, pObjStorage); }; // Allocates memory and constructs object of type 'T' // // Note: This method is respects the alignment of 'T' via C99 alignof() template T* New() { AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock); void* pObjStorage = Pool.Allocate(sizeof(T), alignof(T)); if (pObjStorage == NULL) { CryFatalError("**** could not allocate %d bytes from temporary pool", (int)sizeof (T)); } return Construct(InplaceFactory(), pObjStorage); }; // Frees a block of memory from the temporary pool // void Free(void* ptr) { AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock); Pool.Free(ptr); } // Destroys an object of type 'T' and frees the underlying block of memory template void Delete(T* ptr) { AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock); Pool.Free(Destruct(ptr)); } // Static function to retrieve the static instance of CTemporaryPool static CTemporaryPool* Get() { return s_Instance; }; void GetMemoryUsage(ICrySizer* pSizer) const { pSizer->AddObject(Pool.Data(), Pool.MemSize()); } }; // A stl compliant scratch allocator that uses the given temporary pool. template class scratch_allocator { public: typedef Type value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; template struct rebind { typedef scratch_allocator other; }; scratch_allocator() {} template scratch_allocator(const scratch_allocator&) {} scratch_allocator(const scratch_allocator&) {} ~scratch_allocator() {} pointer address(reference x) const {return &x; } const_pointer address(const_reference x) const { return &x; } // Note: size can be zero - return value will be null in that case value_type* allocate(size_type n, const void* = 0) { if (n != 0) { size_type buf_size = n * sizeof(value_type); void* ret = CTemporaryPool::Get()->Allocate( buf_size, alignof(value_type)); return reinterpret_cast(ret); } return 0; } // Note: size can be zero. void deallocate(pointer p, size_type n) { if (p != NULL) { CTemporaryPool::Get()->Free(p); } } size_type max_size() const { return size_t(-1) / sizeof(value_type); } void construct(pointer p, const_reference val) { new (reinterpret_cast(p))value_type(val); } void destroy(pointer p) { p->~value_type(); } void cleanup() {} size_t get_heap_size() { return 0; } size_t get_wasted_in_allocation() { return 0; } size_t get_wasted_in_blocks() { return 0; } }; // A scratch vector type to use the stl vector template class scratch_vector : public std::vector > { }; namespace util { extern void* pool_allocate(size_t nSize); extern void pool_free(void* ptr); } #endif // CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H