1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
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 *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
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. *
21 *************************************************************************/
32 void dInternalHandleAutoDisabling (dxWorld
*world
, dReal stepsize
);
33 void dxStepBody (dxBody
*b
, dReal h
);
36 struct dxWorldProcessMemoryManager
:
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
)
51 m_fnShrink
= fnShrink
;
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
:
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
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
;
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
);
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
);
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
));
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
; }
186 static sizeint
AdjustArenaSizeForReserveRequirements(sizeint arenareq
, float rsrvfactor
, unsigned rsrvminimum
);
189 void *m_pAllocCurrentOrNextArena
;
194 const dxWorldProcessMemoryManager
*m_pArenaMemMgr
;
197 class dxWorldProcessContext
:
201 dxWorldProcessContext();
202 ~dxWorldProcessContext();
204 void CleanupWorldReferences(dxWorld
*pswWorldInstance
);
207 bool EnsureStepperSyncObjectsAreAllocated(dxWorld
*pswWorldInstance
);
208 dCallWaitID
GetIslandsSteppingWait() const { return m_pcwIslandsSteppingWait
; }
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
);
220 static void FreeArenasList(dxWorldProcessMemArena
*pmaExistingArenas
);
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
);
234 void LockForAddLimotSerialization();
235 void UnlockForAddLimotSerialization();
236 void LockForStepbodySerialization();
237 void UnlockForStepbodySerialization();
240 enum dxProcessContextMutex
242 dxPCM_STEPPER_ARENA_OBTAIN
,
243 dxPCM_STEPPER_ADDLIMOT_SERIALIZE
,
244 dxPCM_STEPPER_STEPBODY_SERIALIZE
,
249 static const char *const m_aszContextMutexNames
[dxPCM__MAX
];
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
;
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
; }
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
:
360 dxStepWorkingMemory(): m_uiRefCount(1), m_ppcProcessingContext(NULL
), m_priReserveInfo(NULL
), m_pmmMemoryManager(NULL
) {}
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
;
374 dIASSERT(~m_uiRefCount
!= 0);
380 dIASSERT(m_uiRefCount
!= 0);
381 if (--m_uiRefCount
== 0)
390 delete m_ppcProcessingContext
;
391 m_ppcProcessingContext
= NULL
;
394 void CleanupWorldReferences(dxWorld
*world
)
396 if (m_ppcProcessingContext
!= NULL
)
398 m_ppcProcessingContext
->CleanupWorldReferences(world
);
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
; }
433 unsigned m_uiRefCount
;
434 dxWorldProcessContext
*m_ppcProcessingContext
;
435 dxWorldProcessMemoryReserveInfo
*m_priReserveInfo
;
436 dxWorldProcessMemoryManager
*m_pmmMemoryManager
;