Files
o3de/Code/CryEngine/Cry3DEngine/3DEngineMemory.h
T
2021-03-08 14:30:57 -08:00

287 lines
8.7 KiB
C++

/*
* 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 <CryPool/PoolAlloc.h>
#include <InplaceFactory.h>
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<CInPlace<CMemoryDynamic>, 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<uint8*>(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<T, Expr> function below. Returns a typed
// pointer to the inplace constructed object.
template<typename T, typename InPlaceFactory>
T* Construct(const InPlaceFactory& factory, void* storage)
{
return reinterpret_cast<T*>(factory.template apply<T>(storage));
}
// Templated destruct helper member function.
//
// Calls the object's destructor and returns a void pointer to the storage
template<typename T>
void* Destruct(T* obj)
{
obj->~T();
return reinterpret_cast<void*>(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<void*>(size, align);
if (pData == NULL)
{
CryFatalError("**** could not allocate %" PRISIZE_T " bytes from temporary pool", size);
}
return Pool.Resolve<void*>(pData);
};
// Allocates memory and constructs object of type 'T'
//
// Note: This method is respects the alignment of 'T' via C99 alignof()
template<typename T, typename Expr>
T* New(const Expr& expr)
{
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
if (pObjStorage == NULL)
{
CryFatalError("**** could not allocate %d bytes from temporary pool",
(int)sizeof (T));
}
return Construct<T>(expr, pObjStorage);
};
// Allocates memory and constructs object of type 'T'
//
// Note: This method is respects the alignment of 'T' via C99 alignof()
template<typename T>
T* New()
{
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
if (pObjStorage == NULL)
{
CryFatalError("**** could not allocate %d bytes from temporary pool",
(int)sizeof (T));
}
return Construct<T>(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<typename T>
void Delete(T* ptr)
{
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
Pool.Free(Destruct<T>(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 Type>
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 <class value_type1>
struct rebind
{
typedef scratch_allocator<value_type1> other;
};
scratch_allocator() {}
template <class value_type1>
scratch_allocator(const scratch_allocator<value_type1>&) {}
scratch_allocator(const scratch_allocator<value_type>&) {}
~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<value_type*>(ret);
}
return 0;
}
// Note: size can be zero.
void deallocate(pointer p, [[maybe_unused]] 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<void*>(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<typename Type>
class scratch_vector
: public std::vector<Type, scratch_allocator<Type> >
{
};
namespace util
{
extern void* pool_allocate(size_t nSize);
extern void pool_free(void* ptr);
}
#endif // CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H