ovr_sdk

annotate LibOVR/Src/Kernel/OVR_Allocator.h @ 0:1b39a1b46319

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