Add a TriMesh to TriMesh collision demo.
[ode.git] / ode / src / util.h
blobca222accb8a37018b176b4d76ae9d14c64e717a6
1 /*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
12 * file LICENSE.TXT. *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
15 * *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
20 * *
21 *************************************************************************/
23 #ifndef _ODE_UTIL_H_
24 #define _ODE_UTIL_H_
26 #include "objects.h"
27 #include "common.h"
30 /* utility */
32 void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize);
33 void dxStepBody (dxBody *b, dReal h);
36 struct dxWorldProcessMemoryManager:
37 public dBase
39 typedef void *(*alloc_block_fn_t)(sizeint block_size);
40 typedef void *(*shrink_block_fn_t)(void *block_pointer, sizeint block_current_size, sizeint block_smaller_size);
41 typedef void (*free_block_fn_t)(void *block_pointer, sizeint block_current_size);
43 dxWorldProcessMemoryManager(alloc_block_fn_t fnAlloc, shrink_block_fn_t fnShrink, free_block_fn_t fnFree)
45 Assign(fnAlloc, fnShrink, fnFree);
48 void Assign(alloc_block_fn_t fnAlloc, shrink_block_fn_t fnShrink, free_block_fn_t fnFree)
50 m_fnAlloc = fnAlloc;
51 m_fnShrink = fnShrink;
52 m_fnFree = fnFree;
55 alloc_block_fn_t m_fnAlloc;
56 shrink_block_fn_t m_fnShrink;
57 free_block_fn_t m_fnFree;
60 extern dxWorldProcessMemoryManager g_WorldProcessMallocMemoryManager;
62 struct dxWorldProcessMemoryReserveInfo:
63 public dBase
65 dxWorldProcessMemoryReserveInfo(float fReserveFactor, unsigned uiReserveMinimum)
67 Assign(fReserveFactor, uiReserveMinimum);
70 void Assign(float fReserveFactor, unsigned uiReserveMinimum)
72 m_fReserveFactor = fReserveFactor;
73 m_uiReserveMinimum = uiReserveMinimum;
76 float m_fReserveFactor; // Use float as precision does not matter here
77 unsigned m_uiReserveMinimum;
80 extern dxWorldProcessMemoryReserveInfo g_WorldProcessDefaultReserveInfo;
83 class dxWorldProcessMemArena:
84 private dBase // new/delete must not be called for this class
86 public:
87 #define BUFFER_TO_ARENA_EXTRA (EFFICIENT_ALIGNMENT + dEFFICIENT_SIZE(sizeof(dxWorldProcessMemArena)))
88 static bool IsArenaPossible(sizeint nBufferSize)
90 return SIZE_MAX - BUFFER_TO_ARENA_EXTRA >= nBufferSize; // This ensures there will be no overflow
93 static sizeint MakeBufferSize(sizeint nArenaSize)
95 return nArenaSize - BUFFER_TO_ARENA_EXTRA;
98 static sizeint MakeArenaSize(sizeint nBufferSize)
100 return BUFFER_TO_ARENA_EXTRA + nBufferSize;
102 #undef BUFFER_TO_ARENA_EXTRA
104 bool IsStructureValid() const
106 return m_pAllocBegin != NULL && m_pAllocEnd != NULL && m_pAllocBegin <= m_pAllocEnd
107 && (m_pAllocCurrentOrNextArena == NULL || m_pAllocCurrentOrNextArena == m_pAllocBegin)
108 && m_pArenaBegin != NULL && m_pArenaBegin <= m_pAllocBegin;
111 sizeint GetMemorySize() const
113 return (sizeint)m_pAllocEnd - (sizeint)m_pAllocBegin;
116 void *SaveState() const
118 return m_pAllocCurrentOrNextArena;
121 void RestoreState(void *state)
123 m_pAllocCurrentOrNextArena = state;
126 void ResetState()
128 m_pAllocCurrentOrNextArena = m_pAllocBegin;
131 void *PeekBufferRemainder() const
133 return m_pAllocCurrentOrNextArena;
136 void *AllocateBlock(sizeint size)
138 void *arena = m_pAllocCurrentOrNextArena;
139 m_pAllocCurrentOrNextArena = dOFFSET_EFFICIENTLY(arena, size);
140 dIASSERT(m_pAllocCurrentOrNextArena <= m_pAllocEnd);
141 dIASSERT(dEFFICIENT_PTR(arena) == arena);
143 return arena;
146 void *AllocateOveralignedBlock(sizeint size, unsigned alignment)
148 void *arena = m_pAllocCurrentOrNextArena;
149 m_pAllocCurrentOrNextArena = dOFFSET_OVERALIGNEDLY(arena, size, alignment);
150 dIASSERT(m_pAllocCurrentOrNextArena <= m_pAllocEnd);
152 void *block = dOVERALIGNED_PTR(arena, alignment);
153 return block;
156 template<typename ElementType>
157 ElementType *AllocateArray(sizeint count)
159 return (ElementType *)AllocateBlock(count * sizeof(ElementType));
162 template<typename ElementType>
163 ElementType *AllocateOveralignedArray(sizeint count, unsigned alignment)
165 return (ElementType *)AllocateOveralignedBlock(count * sizeof(ElementType), alignment);
168 template<typename ElementType>
169 void ShrinkArray(ElementType *arr, sizeint oldcount, sizeint newcount)
171 dIASSERT(newcount <= oldcount);
172 dIASSERT(dOFFSET_EFFICIENTLY(arr, oldcount * sizeof(ElementType)) == m_pAllocCurrentOrNextArena);
173 m_pAllocCurrentOrNextArena = dOFFSET_EFFICIENTLY(arr, newcount * sizeof(ElementType));
176 public:
177 static dxWorldProcessMemArena *ReallocateMemArena (
178 dxWorldProcessMemArena *oldarena, sizeint memreq,
179 const dxWorldProcessMemoryManager *memmgr, float rsrvfactor, unsigned rsrvminimum);
180 static void FreeMemArena (dxWorldProcessMemArena *arena);
182 dxWorldProcessMemArena *GetNextMemArena() const { return (dxWorldProcessMemArena *)m_pAllocCurrentOrNextArena; }
183 void SetNextMemArena(dxWorldProcessMemArena *pArenaInstance) { m_pAllocCurrentOrNextArena = pArenaInstance; }
185 private:
186 static sizeint AdjustArenaSizeForReserveRequirements(sizeint arenareq, float rsrvfactor, unsigned rsrvminimum);
188 private:
189 void *m_pAllocCurrentOrNextArena;
190 void *m_pAllocBegin;
191 void *m_pAllocEnd;
192 void *m_pArenaBegin;
194 const dxWorldProcessMemoryManager *m_pArenaMemMgr;
197 class dxWorldProcessContext:
198 public dBase
200 public:
201 dxWorldProcessContext();
202 ~dxWorldProcessContext();
204 void CleanupWorldReferences(dxWorld *pswWorldInstance);
206 public:
207 bool EnsureStepperSyncObjectsAreAllocated(dxWorld *pswWorldInstance);
208 dCallWaitID GetIslandsSteppingWait() const { return m_pcwIslandsSteppingWait; }
210 public:
211 dxWorldProcessMemArena *ObtainStepperMemArena();
212 void ReturnStepperMemArena(dxWorldProcessMemArena *pmaArenaInstance);
214 dxWorldProcessMemArena *ReallocateIslandsMemArena(sizeint nMemoryRequirement,
215 const dxWorldProcessMemoryManager *pmmMemortManager, float fReserveFactor, unsigned uiReserveMinimum);
216 bool ReallocateStepperMemArenas(dxWorld *world, unsigned nIslandThreadsCount, sizeint nMemoryRequirement,
217 const dxWorldProcessMemoryManager *pmmMemortManager, float fReserveFactor, unsigned uiReserveMinimum);
219 private:
220 static void FreeArenasList(dxWorldProcessMemArena *pmaExistingArenas);
222 private:
223 void SetIslandsMemArena(dxWorldProcessMemArena *pmaInstance) { m_pmaIslandsArena = pmaInstance; }
224 dxWorldProcessMemArena *GetIslandsMemArena() const { return m_pmaIslandsArena; }
226 void SetStepperArenasList(dxWorldProcessMemArena *pmaInstance) { m_pmaStepperArenas = pmaInstance; }
227 dxWorldProcessMemArena *GetStepperArenasList() const { return m_pmaStepperArenas; }
229 inline dxWorldProcessMemArena *GetStepperArenasHead() const;
230 inline bool TryExtractingStepperArenasHead(dxWorldProcessMemArena *pmaHeadInstance);
231 inline bool TryInsertingStepperArenasHead(dxWorldProcessMemArena *pmaArenaInstance, dxWorldProcessMemArena *pmaExistingHead);
233 public:
234 void LockForAddLimotSerialization();
235 void UnlockForAddLimotSerialization();
236 void LockForStepbodySerialization();
237 void UnlockForStepbodySerialization();
239 private:
240 enum dxProcessContextMutex
242 dxPCM_STEPPER_ARENA_OBTAIN,
243 dxPCM_STEPPER_ADDLIMOT_SERIALIZE,
244 dxPCM_STEPPER_STEPBODY_SERIALIZE,
246 dxPCM__MAX
249 static const char *const m_aszContextMutexNames[dxPCM__MAX];
251 private:
252 dxWorldProcessMemArena *m_pmaIslandsArena;
253 dxWorldProcessMemArena *volatile m_pmaStepperArenas;
254 dxWorld *m_pswObjectsAllocWorld;
255 dMutexGroupID m_pmgStepperMutexGroup;
256 dCallWaitID m_pcwIslandsSteppingWait;
259 struct dxWorldProcessIslandsInfo
261 void AssignInfo(sizeint islandcount, unsigned int const *islandsizes, dxBody *const *bodies, dxJoint *const *joints)
263 m_IslandCount = islandcount;
264 m_pIslandSizes = islandsizes;
265 m_pBodies = bodies;
266 m_pJoints = joints;
269 sizeint GetIslandsCount() const { return m_IslandCount; }
270 unsigned int const *GetIslandSizes() const { return m_pIslandSizes; }
271 dxBody *const *GetBodiesArray() const { return m_pBodies; }
272 dxJoint *const *GetJointsArray() const { return m_pJoints; }
274 private:
275 sizeint m_IslandCount;
276 unsigned int const *m_pIslandSizes;
277 dxBody *const *m_pBodies;
278 dxJoint *const *m_pJoints;
281 struct dxStepperProcessingCallContext
283 dxStepperProcessingCallContext(dxWorld *world, dReal stepSize, unsigned stepperAllowedThreads,
284 dxWorldProcessMemArena *stepperArena, dxBody *const *islandBodiesStart, dxJoint *const *islandJointsStart):
285 m_world(world), m_stepSize(stepSize), m_stepperArena(stepperArena), m_finalReleasee(NULL),
286 m_islandBodiesStart(islandBodiesStart), m_islandJointsStart(islandJointsStart), m_islandBodiesCount(0), m_islandJointsCount(0),
287 m_stepperAllowedThreads(stepperAllowedThreads)
291 void AssignIslandSelection(dxBody *const *islandBodiesStart, dxJoint *const *islandJointsStart,
292 unsigned islandBodiesCount, unsigned islandJointsCount)
294 m_islandBodiesStart = islandBodiesStart;
295 m_islandJointsStart = islandJointsStart;
296 m_islandBodiesCount = islandBodiesCount;
297 m_islandJointsCount = islandJointsCount;
300 dxBody *const *GetSelectedIslandBodiesEnd() const { return m_islandBodiesStart + m_islandBodiesCount; }
301 dxJoint *const *GetSelectedIslandJointsEnd() const { return m_islandJointsStart + m_islandJointsCount; }
303 void AssignStepperCallFinalReleasee(dCallReleaseeID finalReleasee)
305 m_finalReleasee = finalReleasee;
308 dxWorld *const m_world;
309 dReal const m_stepSize;
310 dxWorldProcessMemArena *m_stepperArena;
311 dCallReleaseeID m_finalReleasee;
312 dxBody *const *m_islandBodiesStart;
313 dxJoint *const *m_islandJointsStart;
314 unsigned m_islandBodiesCount;
315 unsigned m_islandJointsCount;
316 unsigned m_stepperAllowedThreads;
319 #define BEGIN_STATE_SAVE(memarena, state) void *state = memarena->SaveState();
320 #define END_STATE_SAVE(memarena, state) memarena->RestoreState(state)
322 typedef void (*dstepper_fn_t) (const dxStepperProcessingCallContext *callContext);
323 typedef unsigned (*dmaxcallcountestimate_fn_t) (unsigned activeThreadCount, unsigned allowedThreadCount);
325 bool dxProcessIslands (dxWorld *world, const dxWorldProcessIslandsInfo &islandsInfo,
326 dReal stepSize, dstepper_fn_t stepper, dmaxcallcountestimate_fn_t maxCallCountEstimator);
329 typedef sizeint (*dmemestimate_fn_t) (dxBody * const *body, unsigned int nb,
330 dxJoint * const *_joint, unsigned int _nj);
332 bool dxReallocateWorldProcessContext (dxWorld *world, dxWorldProcessIslandsInfo &islandsinfo,
333 dReal stepsize, dmemestimate_fn_t stepperestimate);
335 dxWorldProcessMemArena *dxAllocateTemporaryWorldProcessMemArena(
336 sizeint memreq, const dxWorldProcessMemoryManager *memmgr/*=NULL*/, const dxWorldProcessMemoryReserveInfo *reserveinfo/*=NULL*/);
337 void dxFreeTemporaryWorldProcessMemArena(dxWorldProcessMemArena *arena);
340 template<class ClassType>
341 inline ClassType *AllocateOnDemand(ClassType *&pctStorage)
343 ClassType *pctCurrentInstance = pctStorage;
345 if (!pctCurrentInstance)
347 pctCurrentInstance = new ClassType();
348 pctStorage = pctCurrentInstance;
351 return pctCurrentInstance;
355 // World stepping working memory object
356 class dxStepWorkingMemory:
357 public dBase
359 public:
360 dxStepWorkingMemory(): m_uiRefCount(1), m_ppcProcessingContext(NULL), m_priReserveInfo(NULL), m_pmmMemoryManager(NULL) {}
362 private:
363 friend struct dBase; // To avoid GCC warning regarding private destructor
364 ~dxStepWorkingMemory() // Use Release() instead
366 delete m_ppcProcessingContext;
367 delete m_priReserveInfo;
368 delete m_pmmMemoryManager;
371 public:
372 void Addref()
374 dIASSERT(~m_uiRefCount != 0);
375 ++m_uiRefCount;
378 void Release()
380 dIASSERT(m_uiRefCount != 0);
381 if (--m_uiRefCount == 0)
383 delete this;
387 public:
388 void CleanupMemory()
390 delete m_ppcProcessingContext;
391 m_ppcProcessingContext = NULL;
394 void CleanupWorldReferences(dxWorld *world)
396 if (m_ppcProcessingContext != NULL)
398 m_ppcProcessingContext->CleanupWorldReferences(world);
402 public:
403 dxWorldProcessContext *SureGetWorldProcessingContext() { return AllocateOnDemand(m_ppcProcessingContext); }
404 dxWorldProcessContext *GetWorldProcessingContext() const { return m_ppcProcessingContext; }
406 const dxWorldProcessMemoryReserveInfo *GetMemoryReserveInfo() const { return m_priReserveInfo; }
407 const dxWorldProcessMemoryReserveInfo *SureGetMemoryReserveInfo() const { return m_priReserveInfo ? m_priReserveInfo : &g_WorldProcessDefaultReserveInfo; }
408 void SetMemoryReserveInfo(float fReserveFactor, unsigned uiReserveMinimum)
410 if (m_priReserveInfo) { m_priReserveInfo->Assign(fReserveFactor, uiReserveMinimum); }
411 else { m_priReserveInfo = new dxWorldProcessMemoryReserveInfo(fReserveFactor, uiReserveMinimum); }
413 void ResetMemoryReserveInfoToDefault()
415 if (m_priReserveInfo) { delete m_priReserveInfo; m_priReserveInfo = NULL; }
418 const dxWorldProcessMemoryManager *GetMemoryManager() const { return m_pmmMemoryManager; }
419 const dxWorldProcessMemoryManager *SureGetMemoryManager() const { return m_pmmMemoryManager ? m_pmmMemoryManager : &g_WorldProcessMallocMemoryManager; }
420 void SetMemoryManager(dxWorldProcessMemoryManager::alloc_block_fn_t fnAlloc,
421 dxWorldProcessMemoryManager::shrink_block_fn_t fnShrink,
422 dxWorldProcessMemoryManager::free_block_fn_t fnFree)
424 if (m_pmmMemoryManager) { m_pmmMemoryManager->Assign(fnAlloc, fnShrink, fnFree); }
425 else { m_pmmMemoryManager = new dxWorldProcessMemoryManager(fnAlloc, fnShrink, fnFree); }
427 void ResetMemoryManagerToDefault()
429 if (m_pmmMemoryManager) { delete m_pmmMemoryManager; m_pmmMemoryManager = NULL; }
432 private:
433 unsigned m_uiRefCount;
434 dxWorldProcessContext *m_ppcProcessingContext;
435 dxWorldProcessMemoryReserveInfo *m_priReserveInfo;
436 dxWorldProcessMemoryManager *m_pmmMemoryManager;
440 #endif