/* * 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. // Description : Declaration and definition of the CrySizer class, which is used to // calculate the memory usage by the subsystems and components, to help // the artists keep the memory budged low. #ifndef CRYINCLUDE_CRYCOMMON_CRYSIZER_H #define CRYINCLUDE_CRYCOMMON_CRYSIZER_H #pragma once ////////////////////////////////////////////////////////////////////////// // common containers for overloads #include #include "Cry_Math.h" #include #include #include #include #include #include #include // forward declarations for overloads struct AABB; struct SVF_P3F; struct SVF_P3F_C4B_T2F; struct SVF_P3F_C4B_T2S; struct SVF_P3S_C4B_T2S; struct SPipTangents; #ifdef WIN64 #include // workaround for Amd64 compiler #endif #include // <> required for Interfuscator. IResourceCollector namespace AZ { class Vector3; } // flags applicable to the ICrySizer (retrieved via getFlags() method) // enum ICrySizerFlagsEnum { // if this flag is set, during getSize(), the subsystem must count all the objects // it uses in the other subsystems also CSF_RecurseSubsystems = 1 << 0, CSF_Reserved1 = 1 << 1, CSF_Reserved2 = 1 << 2 }; ////////////////////////////////////////////////////////////////////////// // Helper functions to calculate size of the std containers. ////////////////////////////////////////////////////////////////////////// namespace stl { template inline size_t size_of_map(const Map& m) { if (!m.empty()) { return m.size() * sizeof(typename Map::value_type) + m.size() * sizeof(MapLikeStruct); } return 0; } template inline size_t size_of_set(const Map& m) { if (!m.empty()) { return m.size() * sizeof(typename Map::value_type) + m.size() * sizeof(MapLikeStruct); } return 0; } template inline size_t size_of_list(const List& c) { if (!c.empty()) { return c.size() * sizeof(typename List::value_type) + c.size() * sizeof(void*) * 2; // sizeof stored type + 2 pointers prev,next } return 0; } template inline size_t size_of_deque(const Deque& c) { if (!c.empty()) { return c.size() * sizeof(typename Deque::value_type); } return 0; } }; ////////////////////////////////////////////////////////////////////////// // interface ICrySizer // USAGE // An instance of this class is passed down to each and every component in the system. // Every component it's passed to optionally pushes its name on top of the // component name stack (thus ensuring that all the components calculated down // the tree will be assigned the correct subsystem/component name) // Every component must Add its size with one of the Add* functions, and Add the // size of all its subcomponents recursively // In order to push the component/system name on the name stack, the clients must // use the SIZER_COMPONENT_NAME macro or CrySizerComponentNameHelper class: // // void X::getSize (ICrySizer* pSizer) // { // SIZER_COMPONENT_NAME(pSizer, X); // if (!pSizer->Add (this)) // return; // pSizer->Add (m_arrMySimpleArray); // pSizer->Add (m_setMySimpleSet); // m_pSubobject->getSize (pSizer); // } // // The Add* functions return bool. If they return true, then the object has been added // to the set for the first time, and you should go on recursively adding all its children. // If it returns false, then you can spare time and rather not go on into recursion; // however it doesn't reflect on the results: an object that's added more than once is // counted only once. // // WARNING: // If you have an array (pointer), you should Add its size with addArray class ICrySizer { public: virtual ~ICrySizer(){} // this class is used to push/pop the name to/from the stack automatically // (to exclude stack overruns or underruns at runtime) friend class CrySizerComponentNameHelper; virtual void Release() = 0; // Return total calculated size. virtual size_t GetTotalSize() = 0; // Return total objects added. virtual size_t GetObjectCount() = 0; // Resets the counting. virtual void Reset() = 0; virtual void End() = 0; // adds an object identified by the unique pointer (it needs not be // the actual object position in the memory, though it would be nice, // but it must be unique throughout the system and unchanging for this object) // nCount parameter is only used for counting number of objects, it doesnt affect the size of the object. // RETURNS: true if the object has actually been added (for the first time) // and calculated virtual bool AddObject (const void* pIdentifier, size_t nSizeBytes, int nCount = 1) = 0; template bool AddObjectSize(const Type* pObj) { return AddObject(pObj, sizeof *pObj); } //////////////////////////////////////////////////////////////////////////////////////// // temp dummy function while checking in the CrySizer changes, will be removed soon template void AddObject(const Type& rObj) { (void)rObj; } template void AddObject(Type* pObj) { if (pObj) { //forward to reference object to allow function overload this->AddObject(*pObj); } } // overloads for smart_ptr and other common objects template void AddObject(const _smart_ptr& rObj) { this->AddObject(rObj.get()); } template void AddObject(const AZStd::shared_ptr& rObj) { this->AddObject(rObj.get()); } template void AddObject(const std::shared_ptr& rObj) { this->AddObject(rObj.get()); } template void AddObject(const std::unique_ptr& rObj) { this->AddObject(rObj.get()); } template void AddObject(const std::pair& rPair) { this->AddObject(rPair.first); this->AddObject(rPair.second); } template void AddObject(const AZStd::pair& rPair) { this->AddObject(rPair.first); this->AddObject(rPair.second); } void AddObject(const string& rString) {this->AddObject(rString.c_str(), rString.capacity()); } void AddObject(const CryStringT& rString) {this->AddObject(rString.c_str(), rString.capacity()); } void AddObject(const CryFixedStringT<32>&){} void AddObject(const wchar_t&) {} void AddObject(const char&) {} void AddObject(const unsigned char&) {} void AddObject(const signed char&) {} void AddObject(const short&) {} void AddObject(const unsigned short&) {} void AddObject(const int&) {} void AddObject(const unsigned int&) {} void AddObject(const long&) {} void AddObject(const unsigned long&) {} void AddObject(const float&) {} void AddObject(const bool&) {} void AddObject(const unsigned long long&) {} void AddObject(const long long&) {} void AddObject(const double&) {} void AddObject(const Vec2&) {} void AddObject(const Vec3&) {} void AddObject(const Vec4&) {} void AddObject(const Ang3&) {} void AddObject(const Matrix34&) {} void AddObject(const Quat&) {} void AddObject(const QuatT&) {} void AddObject(const QuatTS&) {} void AddObject(const ColorF&) {} void AddObject(const AABB&) {} void AddObject(const SVF_P3F&) {} void AddObject(const SVF_P3F_C4B_T2F&) {} void AddObject(const SVF_P3F_C4B_T2S&) {} void AddObject(const SVF_P3S_C4B_T2S&) {} void AddObject(const SPipTangents&) {} void AddObject(const AZ::Vector3& rObj) {} void AddObject(void*) {} template void AddObject(const Array2d& array2d) { this->AddObject(array2d.m_pData, array2d.GetDataSize()); } // overloads for container, will automaticly traverse the content template void AddObject(const std::list& rList) { // dummy struct to get correct element size struct Dummy { void* a; void* b; T t; }; for (typename std::list::const_iterator it = rList.begin(); it != rList.end(); ++it) { if (this->AddObject(&(*it), sizeof(Dummy))) { this->AddObject(*it); } } } template void AddObject(const AZStd::unordered_map& rVector) { } template void AddObject(const std::vector& rVector) { if (rVector.empty()) { this->AddObject(&rVector, rVector.capacity() * sizeof(T)); return; } if (!this->AddObject(&rVector[0], rVector.capacity() * sizeof(T))) { return; } for (typename std::vector::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { this->AddObject(*it); } } template void AddObject(const std::deque& rVector) { for (typename std::deque::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { if (this->AddObject(&(*it), sizeof(T))) { this->AddObject(*it); } } } template void AddObject(const DynArray& rVector) { if (rVector.empty()) { this->AddObject(rVector.begin(), rVector.get_alloc_size()); return; } if (!this->AddObject(rVector.begin(), rVector.get_alloc_size())) { return; } for (typename DynArray::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { this->AddObject(*it); } } template void AddObject(const TArray& rVector) { if (!this->AddObject(rVector.begin(), rVector.capacity() * sizeof(T))) { return; } for (int i = 0, end = rVector.size(); i < end; ++i) { this->AddObject(rVector[i]); } } template void AddObject(const PodArray& rVector) { if (!this->AddObject(rVector.begin(), rVector.capacity() * sizeof(T))) { return; } for (typename PodArray::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { this->AddObject(*it); } } template void AddObject(const std::map& rVector) { // dummy struct to get correct element size struct Dummy { void* a; void* b; void* c; void* d; K k; T t; }; for (typename std::map::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { if (this->AddObject(&(*it), sizeof(Dummy))) { this->AddObject(it->first); this->AddObject(it->second); } } } template void AddObject(const std::set& rVector) { // dummy struct to get correct element size struct Dummy { void* a; void* b; void* c; void* d; T t; }; for (typename std::set::const_iterator it = rVector.begin(); it != rVector.end(); ++it) { if (this->AddObject(&(*it), sizeof(Dummy))) { this->AddObject(*it); } } } template void AddObject (const std::multimap& rContainer) { AddContainer(rContainer); } //////////////////////////////////////////////////////////////////////////////////////// template bool Add (const T* pId, size_t num) { return AddObject(pId, num * sizeof(T)); } template bool Add (const T& rObject) { return AddObject (&rObject, sizeof(T)); } // used to collect the assets needed for streaming and to gather statistics // always returns a valid reference virtual IResourceCollector* GetResourceCollector() = 0; virtual void SetResourceCollector(IResourceCollector* pColl) = 0; bool Add (const char* szText) { return AddObject(szText, strlen(szText) + 1); } template bool AddString (const StringCls& strText) { if (!strText.empty()) { return AddObject (strText.c_str(), strText.size()); } else { return false; } } #ifdef _XSTRING_ template bool Add (const std::basic_string& strText) { AddString (strText); return true; } #endif #ifndef NOT_USE_CRY_STRING bool Add (const string& strText) { AddString(strText); return true; } #endif // Template helper function to add generic stl container template bool AddContainer (const Container& rContainer) { if (rContainer.capacity()) { return AddObject (&rContainer, rContainer.capacity() * sizeof(typename Container::value_type)); } return false; } template bool AddHashMap(const Container& rContainer) { if (!rContainer.empty()) { return AddObject (&(*rContainer.begin()), rContainer.size() * sizeof(typename Container::value_type)); } return false; } // Specialization of the AddContainer for the std::list template bool AddContainer (const std::list& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), stl::size_of_list(rContainer)); } return false; } // Specialization of the AddContainer for the std::deque template bool AddContainer (const std::deque& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), stl::size_of_deque(rContainer)); } return false; } // Specialization of the AddContainer for the std::map template bool AddContainer (const std::map& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), stl::size_of_map(rContainer)); } return false; } // Specialization of the AddContainer for the std::multimap template bool AddContainer (const std::multimap& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), stl::size_of_map(rContainer)); } return false; } // Specialization of the AddContainer for the std::set template bool AddContainer (const std::set& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), stl::size_of_set(rContainer)); } return false; } // Specialization of the AddContainer for the AZStd::unordered_map template bool AddContainer(const AZStd::unordered_map& rContainer) { if (!rContainer.empty()) { return AddObject(&(*rContainer.begin()), rContainer.size() * sizeof(typename AZStd::unordered_map::value_type)); } else { return false; } } void Test() { std::map mymap; AddContainer(mymap); } // returns the flags unsigned GetFlags() const {return m_nFlags; } protected: // these functions must operate on the component name stack // they are to be only accessible from within class CrySizerComponentNameHelper // which should be used through macro SIZER_COMPONENT_NAME virtual void Push (const char* szComponentName) = 0; // pushes the name that is the name of the previous component . (dot) this name virtual void PushSubcomponent (const char* szSubcomponentName) = 0; virtual void Pop () = 0; unsigned m_nFlags; }; ////////////////////////////////////////////////////////////////////////// // This is on-stack class that is only used to push/pop component names // to/from the sizer name stack. // // USAGE: // // Create an instance of this class at the start of a function, before // calling Add* methods of the sizer interface. Everything added in the // function and below will be considered this component, unless // explicitly set otherwise. // class CrySizerComponentNameHelper { public: // pushes the component name on top of the name stack of the given sizer CrySizerComponentNameHelper (ICrySizer* pSizer, const char* szComponentName, bool bSubcomponent) : m_pSizer(pSizer) { if (bSubcomponent) { pSizer->PushSubcomponent (szComponentName); } else { pSizer->Push (szComponentName); } } // pops the component name off top of the name stack of the sizer ~CrySizerComponentNameHelper() { m_pSizer->Pop(); } protected: ICrySizer* m_pSizer; }; // use this to push (and automatically pop) the sizer component name at the beginning of the // getSize() function #define SIZER_COMPONENT_NAME(pSizerPointer, szComponentName) PREFAST_SUPPRESS_WARNING(6246) CrySizerComponentNameHelper AZ_JOIN(sizerHelper, __LINE__)(pSizerPointer, szComponentName, false) #define SIZER_SUBCOMPONENT_NAME(pSizerPointer, szComponentName) PREFAST_SUPPRESS_WARNING(6246) CrySizerComponentNameHelper AZ_JOIN(sizerHelper, __LINE__)(pSizerPointer, szComponentName, true) #endif // CRYINCLUDE_CRYCOMMON_CRYSIZER_H