|
@@ -200,8 +200,9 @@ void ContactConstraintManager::CachedBodyPair::RestoreState(StateRecorder &inStr
|
|
|
|
|
|
void ContactConstraintManager::ManifoldCache::Init(uint inMaxBodyPairs, uint inMaxContactConstraints, uint inCachedManifoldsSize)
|
|
|
{
|
|
|
- mCachedManifolds.Init(inCachedManifoldsSize, GetNextPowerOf2(inMaxContactConstraints));
|
|
|
- mCachedBodyPairs.Init(inMaxBodyPairs * sizeof(BodyPairMap::KeyValue), GetNextPowerOf2(inMaxBodyPairs));
|
|
|
+ mAllocator.Init(inMaxBodyPairs * sizeof(BodyPairMap::KeyValue) + inCachedManifoldsSize);
|
|
|
+ mCachedManifolds.Init(GetNextPowerOf2(inMaxContactConstraints));
|
|
|
+ mCachedBodyPairs.Init(GetNextPowerOf2(inMaxBodyPairs));
|
|
|
}
|
|
|
|
|
|
void ContactConstraintManager::ManifoldCache::Clear()
|
|
@@ -210,6 +211,7 @@ void ContactConstraintManager::ManifoldCache::Clear()
|
|
|
|
|
|
mCachedManifolds.Clear();
|
|
|
mCachedBodyPairs.Clear();
|
|
|
+ mAllocator.Clear();
|
|
|
|
|
|
#ifdef JPH_ENABLE_ASSERTS
|
|
|
// Mark as incomplete
|
|
@@ -217,16 +219,14 @@ void ContactConstraintManager::ManifoldCache::Clear()
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-void ContactConstraintManager::ManifoldCache::Prepare(const ManifoldCache &inReadCache)
|
|
|
+void ContactConstraintManager::ManifoldCache::Prepare(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
|
|
|
{
|
|
|
- JPH_ASSERT(this != &inReadCache);
|
|
|
-
|
|
|
// Minimum amount of buckets to use in the hash map
|
|
|
constexpr uint32 cMinBuckets = 1024;
|
|
|
|
|
|
// Use the next higher power of 2 of amount of objects in the cache from last frame to determine the amount of buckets in this frame
|
|
|
- mCachedManifolds.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inReadCache.mCachedManifolds.GetNumKeyValues())), mCachedManifolds.GetMaxBuckets()));
|
|
|
- mCachedBodyPairs.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inReadCache.mCachedBodyPairs.GetNumKeyValues())), mCachedBodyPairs.GetMaxBuckets()));
|
|
|
+ mCachedManifolds.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inExpectedNumManifolds)), mCachedManifolds.GetMaxBuckets()));
|
|
|
+ mCachedBodyPairs.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inExpectedNumBodyPairs)), mCachedBodyPairs.GetMaxBuckets()));
|
|
|
}
|
|
|
|
|
|
const ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::Find(const SubShapeIDPair &inKey, size_t inKeyHash) const
|
|
@@ -235,26 +235,27 @@ const ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCac
|
|
|
return mCachedManifolds.Find(inKey, inKeyHash);
|
|
|
}
|
|
|
|
|
|
-ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::Create(const SubShapeIDPair &inKey, size_t inKeyHash, int inNumContactPoints)
|
|
|
+ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::Create(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, size_t inKeyHash, int inNumContactPoints)
|
|
|
{
|
|
|
JPH_ASSERT(!mIsFinalized);
|
|
|
- MKeyValue *kv = mCachedManifolds.Create(inKey, inKeyHash, CachedManifold::sGetRequiredExtraSize(inNumContactPoints));
|
|
|
+ MKeyValue *kv = mCachedManifolds.Create(ioContactAllocator, inKey, inKeyHash, CachedManifold::sGetRequiredExtraSize(inNumContactPoints));
|
|
|
if (kv == nullptr)
|
|
|
{
|
|
|
JPH_ASSERT(false, "Out of cache space for manifold cache");
|
|
|
return nullptr;
|
|
|
}
|
|
|
kv->GetValue().mNumContactPoints = uint16(inNumContactPoints);
|
|
|
+ ++ioContactAllocator.mNumManifolds;
|
|
|
return kv;
|
|
|
}
|
|
|
|
|
|
-ContactConstraintManager::MKVAndCreated ContactConstraintManager::ManifoldCache::FindOrCreate(const SubShapeIDPair &inKey, size_t inKeyHash, int inNumContactPoints)
|
|
|
+ContactConstraintManager::MKVAndCreated ContactConstraintManager::ManifoldCache::FindOrCreate(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, size_t inKeyHash, int inNumContactPoints)
|
|
|
{
|
|
|
MKeyValue *kv = const_cast<MKeyValue *>(mCachedManifolds.Find(inKey, inKeyHash));
|
|
|
if (kv != nullptr)
|
|
|
return { kv, false };
|
|
|
|
|
|
- return { Create(inKey, inKeyHash, inNumContactPoints), true };
|
|
|
+ return { Create(ioContactAllocator, inKey, inKeyHash, inNumContactPoints), true };
|
|
|
}
|
|
|
|
|
|
uint32 ContactConstraintManager::ManifoldCache::ToHandle(const MKeyValue *inKeyValue) const
|
|
@@ -275,15 +276,16 @@ const ContactConstraintManager::BPKeyValue *ContactConstraintManager::ManifoldCa
|
|
|
return mCachedBodyPairs.Find(inKey, inKeyHash);
|
|
|
}
|
|
|
|
|
|
-ContactConstraintManager::BPKeyValue *ContactConstraintManager::ManifoldCache::Create(const BodyPair &inKey, size_t inKeyHash)
|
|
|
+ContactConstraintManager::BPKeyValue *ContactConstraintManager::ManifoldCache::Create(ContactAllocator &ioContactAllocator, const BodyPair &inKey, size_t inKeyHash)
|
|
|
{
|
|
|
JPH_ASSERT(!mIsFinalized);
|
|
|
- BPKeyValue *kv = mCachedBodyPairs.Create(inKey, inKeyHash, 0);
|
|
|
+ BPKeyValue *kv = mCachedBodyPairs.Create(ioContactAllocator, inKey, inKeyHash, 0);
|
|
|
if (kv == nullptr)
|
|
|
{
|
|
|
JPH_ASSERT(false, "Out of cache space for body pair cache");
|
|
|
return nullptr;
|
|
|
}
|
|
|
+ ++ioContactAllocator.mNumBodyPairs;
|
|
|
return kv;
|
|
|
}
|
|
|
|
|
@@ -424,6 +426,9 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache &
|
|
|
|
|
|
bool success = true;
|
|
|
|
|
|
+ // Create a contact allocator for restoring the contact cache
|
|
|
+ ContactAllocator contact_allocator(GetContactAllocator());
|
|
|
+
|
|
|
// When validating, get all existing body pairs
|
|
|
vector<const BPKeyValue *> all_bp;
|
|
|
if (inStream.IsValidating())
|
|
@@ -446,7 +451,7 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache &
|
|
|
|
|
|
// Create new entry for this body pair
|
|
|
size_t body_pair_hash = BodyPairHash {} (body_pair_key);
|
|
|
- BPKeyValue *bp_kv = Create(body_pair_key, body_pair_hash);
|
|
|
+ BPKeyValue *bp_kv = Create(contact_allocator, body_pair_key, body_pair_hash);
|
|
|
if (bp_kv == nullptr)
|
|
|
{
|
|
|
// Out of cache space
|
|
@@ -488,7 +493,7 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache &
|
|
|
inStream.Read(num_contact_points);
|
|
|
|
|
|
// Read manifold
|
|
|
- MKeyValue *m_kv = Create(sub_shape_key, sub_shape_key_hash, num_contact_points);
|
|
|
+ MKeyValue *m_kv = Create(contact_allocator, sub_shape_key, sub_shape_key_hash, num_contact_points);
|
|
|
if (m_kv == nullptr)
|
|
|
{
|
|
|
// Out of cache space
|
|
@@ -533,7 +538,7 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache &
|
|
|
size_t sub_shape_key_hash = std::hash<SubShapeIDPair> {} (sub_shape_key);
|
|
|
|
|
|
// Create CCD manifold
|
|
|
- MKeyValue *m_kv = Create(sub_shape_key, sub_shape_key_hash, 0);
|
|
|
+ MKeyValue *m_kv = Create(contact_allocator, sub_shape_key, sub_shape_key_hash, 0);
|
|
|
if (m_kv == nullptr)
|
|
|
{
|
|
|
// Out of cache space
|
|
@@ -589,13 +594,10 @@ void ContactConstraintManager::PrepareConstraintBuffer(PhysicsUpdateContext *inC
|
|
|
// Allocate temporary constraint buffer
|
|
|
JPH_ASSERT(mConstraints == nullptr);
|
|
|
mConstraints = (ContactConstraint *)inContext->mTempAllocator->Allocate(mMaxConstraints * sizeof(ContactConstraint));
|
|
|
-
|
|
|
- // Use the amount of contacts from the last iteration to determine the amount of buckets to use in the hash map for this frame
|
|
|
- mCache[mCacheWriteIdx].Prepare(mCache[mCacheWriteIdx ^ 1]);
|
|
|
}
|
|
|
|
|
|
// Get the orientation of body 2 in local space of body 1
|
|
|
-static void sGetRelativeOrientation(const Body &inBody1, const Body &inBody2, Vec3 &outDeltaPosition, Quat &outDeltaRotation)
|
|
|
+static JPH_INLINE void sGetRelativeOrientation(const Body &inBody1, const Body &inBody2, Vec3 &outDeltaPosition, Quat &outDeltaRotation)
|
|
|
{
|
|
|
Quat inv_r1 = inBody1.GetRotation().Conjugated();
|
|
|
|
|
@@ -610,7 +612,7 @@ static void sGetRelativeOrientation(const Body &inBody1, const Body &inBody2, Ve
|
|
|
outDeltaPosition = inv_r1 * (inBody2.GetCenterOfMassPosition() - inBody1.GetCenterOfMassPosition());
|
|
|
}
|
|
|
|
|
|
-void ContactConstraintManager::GetContactsFromCache(Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outContactFound)
|
|
|
+void ContactConstraintManager::GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outContactFound)
|
|
|
{
|
|
|
JPH_PROFILE_FUNCTION();
|
|
|
|
|
@@ -663,7 +665,7 @@ void ContactConstraintManager::GetContactsFromCache(Body &inBody1, Body &inBody2
|
|
|
|
|
|
// Copy the cached body pair to this frame
|
|
|
ManifoldCache &write_cache = mCache[mCacheWriteIdx];
|
|
|
- BPKeyValue *output_bp_kv = write_cache.Create(body_pair_key, body_pair_hash);
|
|
|
+ BPKeyValue *output_bp_kv = write_cache.Create(ioContactAllocator, body_pair_key, body_pair_hash);
|
|
|
if (output_bp_kv == nullptr)
|
|
|
return; // Out of cache space
|
|
|
CachedBodyPair *output_cbp = &output_bp_kv->GetValue();
|
|
@@ -698,7 +700,7 @@ void ContactConstraintManager::GetContactsFromCache(Body &inBody1, Body &inBody2
|
|
|
|
|
|
// Create room for manifold in write buffer and copy data
|
|
|
size_t input_hash = std::hash<SubShapeIDPair> {} (input_key);
|
|
|
- MKeyValue *output_kv = write_cache.Create(input_key, input_hash, input_cm.mNumContactPoints);
|
|
|
+ MKeyValue *output_kv = write_cache.Create(ioContactAllocator, input_key, input_hash, input_cm.mNumContactPoints);
|
|
|
if (output_kv == nullptr)
|
|
|
break; // Out of cache space
|
|
|
CachedManifold *output_cm = &output_kv->GetValue();
|
|
@@ -802,7 +804,7 @@ void ContactConstraintManager::GetContactsFromCache(Body &inBody1, Body &inBody2
|
|
|
output_cbp->mFirstCachedManifold = output_handle;
|
|
|
}
|
|
|
|
|
|
-ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair(const Body &inBody1, const Body &inBody2)
|
|
|
+ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2)
|
|
|
{
|
|
|
JPH_PROFILE_FUNCTION();
|
|
|
|
|
@@ -822,7 +824,7 @@ ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair(c
|
|
|
// Add an entry
|
|
|
BodyPair body_pair_key(body1->GetID(), body2->GetID());
|
|
|
size_t body_pair_hash = BodyPairHash {} (body_pair_key);
|
|
|
- BPKeyValue *body_pair_kv = mCache[mCacheWriteIdx].Create(body_pair_key, body_pair_hash);
|
|
|
+ BPKeyValue *body_pair_kv = mCache[mCacheWriteIdx].Create(ioContactAllocator, body_pair_key, body_pair_hash);
|
|
|
if (body_pair_kv == nullptr)
|
|
|
return nullptr; // Out of cache space
|
|
|
CachedBodyPair *cbp = &body_pair_kv->GetValue();
|
|
@@ -840,7 +842,7 @@ ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair(c
|
|
|
return cbp;
|
|
|
}
|
|
|
|
|
|
-void ContactConstraintManager::AddContactConstraint(BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold)
|
|
|
+void ContactConstraintManager::AddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold)
|
|
|
{
|
|
|
JPH_PROFILE_FUNCTION();
|
|
|
|
|
@@ -877,7 +879,7 @@ void ContactConstraintManager::AddContactConstraint(BodyPairHandle inBodyPairHan
|
|
|
// Note that for dynamic vs dynamic we always require the first body to have a lower body id to get a consistent key
|
|
|
// under which to look up the contact
|
|
|
ManifoldCache &write_cache = mCache[mCacheWriteIdx];
|
|
|
- MKeyValue *new_manifold_kv = write_cache.Create(key, key_hash, num_contact_points);
|
|
|
+ MKeyValue *new_manifold_kv = write_cache.Create(ioContactAllocator, key, key_hash, num_contact_points);
|
|
|
if (new_manifold_kv == nullptr)
|
|
|
return; // Out of cache space
|
|
|
CachedManifold *new_manifold = &new_manifold_kv->GetValue();
|
|
@@ -1032,7 +1034,7 @@ void ContactConstraintManager::AddContactConstraint(BodyPairHandle inBodyPairHan
|
|
|
cbp->mFirstCachedManifold = write_cache.ToHandle(new_manifold_kv);
|
|
|
}
|
|
|
|
|
|
-void ContactConstraintManager::OnCCDContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings)
|
|
|
+void ContactConstraintManager::OnCCDContactAdded(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings)
|
|
|
{
|
|
|
JPH_ASSERT(inManifold.mWorldSpaceNormal.IsNormalized());
|
|
|
|
|
@@ -1067,7 +1069,7 @@ void ContactConstraintManager::OnCCDContactAdded(const Body &inBody1, const Body
|
|
|
|
|
|
// Check if we already created this contact this physics update
|
|
|
ManifoldCache &write_cache = mCache[mCacheWriteIdx];
|
|
|
- MKVAndCreated new_manifold_kv = write_cache.FindOrCreate(key, key_hash, 0);
|
|
|
+ MKVAndCreated new_manifold_kv = write_cache.FindOrCreate(ioContactAllocator, key, key_hash, 0);
|
|
|
if (new_manifold_kv.second)
|
|
|
{
|
|
|
// This contact is new for this physics update, check if previous update we already had this contact.
|
|
@@ -1117,15 +1119,25 @@ void ContactConstraintManager::SortContacts(uint32 *inConstraintIdxBegin, uint32
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-void ContactConstraintManager::FinalizeContactCache()
|
|
|
+void ContactConstraintManager::FinalizeContactCache(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
|
|
|
{
|
|
|
JPH_PROFILE_FUNCTION();
|
|
|
|
|
|
- // Buffers are now complete, make write buffer the read buffer
|
|
|
#ifdef JPH_ENABLE_ASSERTS
|
|
|
- mCache[mCacheWriteIdx].Finalize();
|
|
|
+ // Mark cache as finalized
|
|
|
+ ManifoldCache &old_write_cache = mCache[mCacheWriteIdx];
|
|
|
+ old_write_cache.Finalize();
|
|
|
+
|
|
|
+ // Check that the count of body pairs and manifolds that we tracked outside of the cache (to avoid contention on an atomic) is correct
|
|
|
+ JPH_ASSERT(old_write_cache.GetNumBodyPairs() == inExpectedNumBodyPairs);
|
|
|
+ JPH_ASSERT(old_write_cache.GetNumManifolds() == inExpectedNumManifolds);
|
|
|
#endif
|
|
|
+
|
|
|
+ // Buffers are now complete, make write buffer the read buffer
|
|
|
mCacheWriteIdx ^= 1;
|
|
|
+
|
|
|
+ // Use the amount of contacts from the last iteration to determine the amount of buckets to use in the hash map for the next iteration
|
|
|
+ mCache[mCacheWriteIdx].Prepare(inExpectedNumBodyPairs, inExpectedNumManifolds);
|
|
|
}
|
|
|
|
|
|
void ContactConstraintManager::ContactPointRemovedCallbacks()
|
|
@@ -1323,9 +1335,6 @@ bool ContactConstraintManager::SolvePositionConstraints(const uint32 *inConstrai
|
|
|
|
|
|
void ContactConstraintManager::RecycleConstraintBuffer()
|
|
|
{
|
|
|
- // Use the amount of contacts from the last iteration to determine the amount of buckets to use in the hash map for this frame
|
|
|
- mCache[mCacheWriteIdx].Prepare(mCache[mCacheWriteIdx ^ 1]);
|
|
|
-
|
|
|
// Reset constraint array
|
|
|
mNumConstraints = 0;
|
|
|
}
|