oculus1

annotate libovr/Src/Kernel/OVR_Allocator.h @ 29:9a973ef0e2a3

fixed the performance issue under MacOSX by replacing glutSolidTeapot (which uses glEvalMesh) with my own teapot generator.
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 27 Oct 2013 06:31:18 +0200
parents e2f9e4603129
children
rev   line source
nuclear@3 1 /************************************************************************************
nuclear@3 2
nuclear@3 3 PublicHeader: OVR.h
nuclear@3 4 Filename : OVR_Allocator.h
nuclear@3 5 Content : Installable memory allocator
nuclear@3 6 Created : September 19, 2012
nuclear@3 7 Notes :
nuclear@3 8
nuclear@3 9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
nuclear@3 10
nuclear@3 11 Use of this software is subject to the terms of the Oculus license
nuclear@3 12 agreement provided at the time of installation or download, or which
nuclear@3 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@3 14
nuclear@3 15 ************************************************************************************/
nuclear@3 16
nuclear@3 17 #ifndef OVR_Allocator_h
nuclear@3 18 #define OVR_Allocator_h
nuclear@3 19
nuclear@3 20 #include "OVR_Types.h"
nuclear@3 21
nuclear@3 22 //-----------------------------------------------------------------------------------
nuclear@3 23
nuclear@3 24 // ***** Disable template-unfriendly MS VC++ warnings
nuclear@3 25 #if defined(OVR_CC_MSVC)
nuclear@3 26 // Pragma to prevent long name warnings in in VC++
nuclear@3 27 #pragma warning(disable : 4503)
nuclear@3 28 #pragma warning(disable : 4786)
nuclear@3 29 // In MSVC 7.1, warning about placement new POD default initializer
nuclear@3 30 #pragma warning(disable : 4345)
nuclear@3 31 #endif
nuclear@3 32
nuclear@3 33 // Un-define new so that placement constructors work
nuclear@3 34 #undef new
nuclear@3 35
nuclear@3 36
nuclear@3 37 //-----------------------------------------------------------------------------------
nuclear@3 38 // ***** Placement new overrides
nuclear@3 39
nuclear@3 40 // Calls constructor on own memory created with "new(ptr) type"
nuclear@3 41 #ifndef __PLACEMENT_NEW_INLINE
nuclear@3 42 #define __PLACEMENT_NEW_INLINE
nuclear@3 43
nuclear@3 44 # if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
nuclear@3 45 # include <new>
nuclear@3 46 # else
nuclear@3 47 // Useful on MSVC
nuclear@3 48 OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
nuclear@3 49 OVR_FORCE_INLINE void operator delete (void *, void *) { }
nuclear@3 50 # endif
nuclear@3 51
nuclear@3 52 #endif // __PLACEMENT_NEW_INLINE
nuclear@3 53
nuclear@3 54
nuclear@3 55
nuclear@3 56 //------------------------------------------------------------------------
nuclear@3 57 // ***** Macros to redefine class new/delete operators
nuclear@3 58
nuclear@3 59 // Types specifically declared to allow disambiguation of address in
nuclear@3 60 // class member operator new.
nuclear@3 61
nuclear@3 62 #define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
nuclear@3 63 void* operator new(UPInt sz) \
nuclear@3 64 { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
nuclear@3 65 void* operator new(UPInt sz, const char* file, int line) \
nuclear@3 66 { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
nuclear@3 67 void operator delete(void *p) \
nuclear@3 68 { check_delete(class_name, p); OVR_FREE(p); } \
nuclear@3 69 void operator delete(void *p, const char*, int) \
nuclear@3 70 { check_delete(class_name, p); OVR_FREE(p); }
nuclear@3 71
nuclear@3 72 #define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
nuclear@3 73 void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
nuclear@3 74 void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
nuclear@3 75
nuclear@3 76
nuclear@3 77 #define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
nuclear@3 78
nuclear@3 79 // Redefined all delete/new operators in a class without custom memory initialization
nuclear@3 80 #define OVR_MEMORY_REDEFINE_NEW(class_name) \
nuclear@3 81 OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
nuclear@3 82
nuclear@3 83
nuclear@3 84 namespace OVR {
nuclear@3 85
nuclear@3 86 //-----------------------------------------------------------------------------------
nuclear@3 87 // ***** Construct / Destruct
nuclear@3 88
nuclear@3 89 // Construct/Destruct functions are useful when new is redefined, as they can
nuclear@3 90 // be called instead of placement new constructors.
nuclear@3 91
nuclear@3 92
nuclear@3 93 template <class T>
nuclear@3 94 OVR_FORCE_INLINE T* Construct(void *p)
nuclear@3 95 {
nuclear@3 96 return ::new(p) T;
nuclear@3 97 }
nuclear@3 98
nuclear@3 99 template <class T>
nuclear@3 100 OVR_FORCE_INLINE T* Construct(void *p, const T& source)
nuclear@3 101 {
nuclear@3 102 return ::new(p) T(source);
nuclear@3 103 }
nuclear@3 104
nuclear@3 105 // Same as above, but allows for a different type of constructor.
nuclear@3 106 template <class T, class S>
nuclear@3 107 OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
nuclear@3 108 {
nuclear@3 109 return ::new(p) T(source);
nuclear@3 110 }
nuclear@3 111
nuclear@3 112 template <class T, class S1, class S2>
nuclear@3 113 OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
nuclear@3 114 {
nuclear@3 115 return ::new(p) T(src1, src2);
nuclear@3 116 }
nuclear@3 117
nuclear@3 118 template <class T>
nuclear@3 119 OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
nuclear@3 120 {
nuclear@3 121 UByte *pdata = (UByte*)p;
nuclear@3 122 for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
nuclear@3 123 {
nuclear@3 124 Construct<T>(pdata);
nuclear@3 125 }
nuclear@3 126 }
nuclear@3 127
nuclear@3 128 template <class T>
nuclear@3 129 OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
nuclear@3 130 {
nuclear@3 131 UByte *pdata = (UByte*)p;
nuclear@3 132 for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
nuclear@3 133 {
nuclear@3 134 Construct<T>(pdata, source);
nuclear@3 135 }
nuclear@3 136 }
nuclear@3 137
nuclear@3 138 template <class T>
nuclear@3 139 OVR_FORCE_INLINE void Destruct(T *pobj)
nuclear@3 140 {
nuclear@3 141 pobj->~T();
nuclear@3 142 OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
nuclear@3 143 }
nuclear@3 144
nuclear@3 145 template <class T>
nuclear@3 146 OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
nuclear@3 147 {
nuclear@3 148 for (UPInt i=0; i<count; ++i, ++pobj)
nuclear@3 149 pobj->~T();
nuclear@3 150 }
nuclear@3 151
nuclear@3 152
nuclear@3 153 //-----------------------------------------------------------------------------------
nuclear@3 154 // ***** Allocator
nuclear@3 155
nuclear@3 156 // Allocator defines a memory allocation interface that developers can override
nuclear@3 157 // to to provide memory for OVR; an instance of this class is typically created on
nuclear@3 158 // application startup and passed into System or OVR::System constructor.
nuclear@3 159 //
nuclear@3 160 //
nuclear@3 161 // Users implementing this interface must provide three functions: Alloc, Free,
nuclear@3 162 // and Realloc. Implementations of these functions must honor the requested alignment.
nuclear@3 163 // Although arbitrary alignment requests are possible, requested alignment will
nuclear@3 164 // typically be small, such as 16 bytes or less.
nuclear@3 165
nuclear@3 166 class Allocator
nuclear@3 167 {
nuclear@3 168 friend class System;
nuclear@3 169 public:
nuclear@3 170
nuclear@3 171 // *** Standard Alignment Alloc/Free
nuclear@3 172
nuclear@3 173 // Allocate memory of specified size with default alignment.
nuclear@3 174 // Alloc of size==0 will allocate a tiny block & return a valid pointer;
nuclear@3 175 // this makes it suitable for new operator.
nuclear@3 176 virtual void* Alloc(UPInt size) = 0;
nuclear@3 177 // Same as Alloc, but provides an option of passing debug data.
nuclear@3 178 virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
nuclear@3 179 { OVR_UNUSED2(file, line); return Alloc(size); }
nuclear@3 180
nuclear@3 181 // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
nuclear@3 182 // new memory block, which may be the same as original pointer. Will return 0 if reallocation
nuclear@3 183 // failed, in which case previous memory is still valid.
nuclear@3 184 // Realloc to decrease size will never fail.
nuclear@3 185 // Realloc of pointer == 0 is equivalent to Alloc
nuclear@3 186 // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
nuclear@3 187 virtual void* Realloc(void* p, UPInt newSize) = 0;
nuclear@3 188
nuclear@3 189 // Frees memory allocated by Alloc/Realloc.
nuclear@3 190 // Free of null pointer is valid and will do nothing.
nuclear@3 191 virtual void Free(void *p) = 0;
nuclear@3 192
nuclear@3 193
nuclear@3 194 // *** Standard Alignment Alloc/Free
nuclear@3 195
nuclear@3 196 // Allocate memory of specified alignment.
nuclear@3 197 // Memory allocated with AllocAligned MUST be freed with FreeAligned.
nuclear@3 198 // Default implementation will delegate to Alloc/Free after doing rounding.
nuclear@3 199 virtual void* AllocAligned(UPInt size, UPInt align);
nuclear@3 200 // Frees memory allocated with AllocAligned.
nuclear@3 201 virtual void FreeAligned(void* p);
nuclear@3 202
nuclear@3 203 // Returns the pointer to the current globally installed Allocator instance.
nuclear@3 204 // This pointer is used for most of the memory allocations.
nuclear@3 205 static Allocator* GetInstance() { return pInstance; }
nuclear@3 206
nuclear@3 207
nuclear@3 208 protected:
nuclear@3 209 // onSystemShutdown is called on the allocator during System::Shutdown.
nuclear@3 210 // At this point, all allocations should've been freed.
nuclear@3 211 virtual void onSystemShutdown() { }
nuclear@3 212
nuclear@3 213 public:
nuclear@3 214 static void setInstance(Allocator* palloc)
nuclear@3 215 {
nuclear@3 216 OVR_ASSERT((pInstance == 0) || (palloc == 0));
nuclear@3 217 pInstance = palloc;
nuclear@3 218 }
nuclear@3 219
nuclear@3 220 private:
nuclear@3 221
nuclear@3 222 static Allocator* pInstance;
nuclear@3 223 };
nuclear@3 224
nuclear@3 225
nuclear@3 226
nuclear@3 227 //------------------------------------------------------------------------
nuclear@3 228 // ***** Allocator_SingletonSupport
nuclear@3 229
nuclear@3 230 // Allocator_SingletonSupport is a Allocator wrapper class that implements
nuclear@3 231 // the InitSystemSingleton static function, used to create a global singleton
nuclear@3 232 // used for the OVR::System default argument initialization.
nuclear@3 233 //
nuclear@3 234 // End users implementing custom Allocator interface don't need to make use of this base
nuclear@3 235 // class; they can just create an instance of their own class on stack and pass it to System.
nuclear@3 236
nuclear@3 237 template<class D>
nuclear@3 238 class Allocator_SingletonSupport : public Allocator
nuclear@3 239 {
nuclear@3 240 struct AllocContainer
nuclear@3 241 {
nuclear@3 242 UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
nuclear@3 243 bool Initialized;
nuclear@3 244 AllocContainer() : Initialized(0) { }
nuclear@3 245 };
nuclear@3 246
nuclear@3 247 AllocContainer* pContainer;
nuclear@3 248
nuclear@3 249 public:
nuclear@3 250 Allocator_SingletonSupport() : pContainer(0) { }
nuclear@3 251
nuclear@3 252 // Creates a singleton instance of this Allocator class used
nuclear@3 253 // on OVR_DEFAULT_ALLOCATOR during System initialization.
nuclear@3 254 static D* InitSystemSingleton()
nuclear@3 255 {
nuclear@3 256 static AllocContainer Container;
nuclear@3 257 OVR_ASSERT(Container.Initialized == false);
nuclear@3 258
nuclear@3 259 Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
nuclear@3 260 presult->pContainer = &Container;
nuclear@3 261 Container.Initialized = true;
nuclear@3 262 return (D*)presult;
nuclear@3 263 }
nuclear@3 264
nuclear@3 265 protected:
nuclear@3 266 virtual void onSystemShutdown()
nuclear@3 267 {
nuclear@3 268 Allocator::onSystemShutdown();
nuclear@3 269 if (pContainer)
nuclear@3 270 {
nuclear@3 271 pContainer->Initialized = false;
nuclear@3 272 Destruct((D*)this);
nuclear@3 273 pContainer = 0;
nuclear@3 274 }
nuclear@3 275 }
nuclear@3 276 };
nuclear@3 277
nuclear@3 278 //------------------------------------------------------------------------
nuclear@3 279 // ***** Default Allocator
nuclear@3 280
nuclear@3 281 // This allocator is created and used if no other allocator is installed.
nuclear@3 282 // Default allocator delegates to system malloc.
nuclear@3 283
nuclear@3 284 class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
nuclear@3 285 {
nuclear@3 286 public:
nuclear@3 287 virtual void* Alloc(UPInt size);
nuclear@3 288 virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
nuclear@3 289 virtual void* Realloc(void* p, UPInt newSize);
nuclear@3 290 virtual void Free(void *p);
nuclear@3 291 };
nuclear@3 292
nuclear@3 293
nuclear@3 294 //------------------------------------------------------------------------
nuclear@3 295 // ***** Memory Allocation Macros
nuclear@3 296
nuclear@3 297 // These macros should be used for global allocation. In the future, these
nuclear@3 298 // macros will allows allocation to be extended with debug file/line information
nuclear@3 299 // if necessary.
nuclear@3 300
nuclear@3 301 #define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
nuclear@3 302 #define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
nuclear@3 303 #define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
nuclear@3 304 #define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
nuclear@3 305
nuclear@3 306 #ifdef OVR_BUILD_DEBUG
nuclear@3 307 #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
nuclear@3 308 #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
nuclear@3 309 #else
nuclear@3 310 #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
nuclear@3 311 #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
nuclear@3 312 #endif
nuclear@3 313
nuclear@3 314 //------------------------------------------------------------------------
nuclear@3 315
nuclear@3 316 // Base class that overrides the new and delete operators.
nuclear@3 317 // Deriving from this class, even as a multiple base, incurs no space overhead.
nuclear@3 318 class NewOverrideBase
nuclear@3 319 {
nuclear@3 320 public:
nuclear@3 321
nuclear@3 322 // Redefine all new & delete operators.
nuclear@3 323 OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
nuclear@3 324 };
nuclear@3 325
nuclear@3 326
nuclear@3 327 } // OVR
nuclear@3 328
nuclear@3 329
nuclear@3 330 // Redefine operator 'new' if necessary.
nuclear@3 331 #if defined(OVR_DEFINE_NEW)
nuclear@3 332 #define new OVR_DEFINE_NEW
nuclear@3 333 #endif
nuclear@3 334
nuclear@3 335
nuclear@3 336 #endif // OVR_Memory