1 | // |
2 | // Redistribution and use in source and binary forms, with or without |
3 | // modification, are permitted provided that the following conditions |
4 | // are met: |
5 | // * Redistributions of source code must retain the above copyright |
6 | // notice, this list of conditions and the following disclaimer. |
7 | // * Redistributions in binary form must reproduce the above copyright |
8 | // notice, this list of conditions and the following disclaimer in the |
9 | // documentation and/or other materials provided with the distribution. |
10 | // * Neither the name of NVIDIA CORPORATION nor the names of its |
11 | // contributors may be used to endorse or promote products derived |
12 | // from this software without specific prior written permission. |
13 | // |
14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
15 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
18 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | // |
26 | // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. |
27 | // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. |
28 | // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. |
29 | |
30 | |
31 | #ifndef PXD_THRESHOLDTABLE_H |
32 | #define PXD_THRESHOLDTABLE_H |
33 | #include "Ps.h" |
34 | #include "PsArray.h" |
35 | #include "CmPhysXCommon.h" |
36 | #include "PsAllocator.h" |
37 | #include "PsHash.h" |
38 | #include "foundation/PxMemory.h" |
39 | #include "PxsIslandNodeIndex.h" |
40 | |
41 | namespace physx |
42 | { |
43 | |
44 | class PxsRigidBody; |
45 | |
46 | namespace Sc |
47 | { |
48 | class ShapeInteraction; |
49 | } |
50 | |
51 | namespace Dy |
52 | { |
53 | |
54 | struct ThresholdStreamElement |
55 | { |
56 | Sc::ShapeInteraction* shapeInteraction; //4 8 |
57 | PxReal normalForce; //8 12 |
58 | PxReal threshold; //12 16 |
59 | IG::NodeIndex nodeIndexA; //this is the unique node index in island gen which corresonding to that body and it is persistent 16 20 |
60 | IG::NodeIndex nodeIndexB; //This is the unique node index in island gen which corresonding to that body and it is persistent 20 24 |
61 | PxReal accumulatedForce; //24 28 |
62 | PxU32 pad; //28 32 |
63 | |
64 | #if !PX_P64_FAMILY |
65 | PxU32 pad1; //32 |
66 | #endif // !PX_X64 |
67 | |
68 | PX_CUDA_CALLABLE bool operator <= (const ThresholdStreamElement& otherPair) const |
69 | { |
70 | return ((nodeIndexA < otherPair.nodeIndexA) ||(nodeIndexA == otherPair.nodeIndexA && nodeIndexB <= otherPair.nodeIndexB)); |
71 | } |
72 | |
73 | }; |
74 | |
75 | typedef Ps::Array<ThresholdStreamElement, Ps::VirtualAllocator> ThresholdArray; |
76 | |
77 | class ThresholdStream : public ThresholdArray |
78 | { |
79 | public: |
80 | ThresholdStream(Ps::VirtualAllocatorCallback& allocatorCallback) : ThresholdArray(Ps::VirtualAllocator(&allocatorCallback)) |
81 | { |
82 | } |
83 | |
84 | }; |
85 | |
86 | class ThresholdTable |
87 | { |
88 | public: |
89 | |
90 | ThresholdTable() |
91 | : mBuffer(NULL), |
92 | mHash(NULL), |
93 | mHashSize(0), |
94 | mHashCapactiy(0), |
95 | mPairs(NULL), |
96 | mNexts(NULL), |
97 | mPairsSize(0), |
98 | mPairsCapacity(0) |
99 | { |
100 | } |
101 | |
102 | ~ThresholdTable() |
103 | { |
104 | if(mBuffer) PX_FREE(mBuffer); |
105 | } |
106 | |
107 | void build(const ThresholdStream& stream); |
108 | |
109 | bool check(const ThresholdStream& stream, const PxU32 nodexIndexA, const PxU32 nodexIndexB, PxReal dt); |
110 | |
111 | bool check(const ThresholdStream& stream, const ThresholdStreamElement& elem, PxU32& thresholdIndex); |
112 | |
113 | //private: |
114 | |
115 | static const PxU32 NO_INDEX = 0xffffffff; |
116 | |
117 | struct Pair |
118 | { |
119 | PxU32 thresholdStreamIndex; |
120 | PxReal accumulatedForce; |
121 | //PxU32 next; // hash key & next ptr |
122 | }; |
123 | |
124 | PxU8* mBuffer; |
125 | |
126 | PxU32* mHash; |
127 | PxU32 mHashSize; |
128 | PxU32 mHashCapactiy; |
129 | |
130 | Pair* mPairs; |
131 | PxU32* mNexts; |
132 | PxU32 ; |
133 | PxU32 mPairsCapacity; |
134 | }; |
135 | |
136 | namespace |
137 | { |
138 | static PX_FORCE_INLINE PxU32 computeHashKey(const PxU32 nodeIndexA, const PxU32 nodeIndexB, const PxU32 hashCapacity) |
139 | { |
140 | return (Ps::hash(key: PxU64(nodeIndexA)<<32 | PxU64(nodeIndexB)) % hashCapacity); |
141 | } |
142 | } |
143 | |
144 | inline bool ThresholdTable::check(const ThresholdStream& stream, const ThresholdStreamElement& elem, PxU32& thresholdIndex) |
145 | { |
146 | PxU32* PX_RESTRICT hashes = mHash; |
147 | PxU32* PX_RESTRICT nextIndices = mNexts; |
148 | Pair* PX_RESTRICT pairs = mPairs; |
149 | |
150 | PX_ASSERT(elem.nodeIndexA < elem.nodeIndexB); |
151 | PxU32 hashKey = computeHashKey(nodeIndexA: elem.nodeIndexA.index(), nodeIndexB: elem.nodeIndexB.index(), hashCapacity: mHashSize); |
152 | |
153 | PxU32 pairIndex = hashes[hashKey]; |
154 | |
155 | while(NO_INDEX != pairIndex) |
156 | { |
157 | Pair& pair = pairs[pairIndex]; |
158 | const PxU32 thresholdStreamIndex = pair.thresholdStreamIndex; |
159 | PX_ASSERT(thresholdStreamIndex < stream.size()); |
160 | const ThresholdStreamElement& otherElement = stream[thresholdStreamIndex]; |
161 | if(otherElement.nodeIndexA==elem.nodeIndexA && otherElement.nodeIndexB==elem.nodeIndexB && otherElement.shapeInteraction == elem.shapeInteraction) |
162 | { |
163 | thresholdIndex = thresholdStreamIndex; |
164 | return true; |
165 | } |
166 | pairIndex = nextIndices[pairIndex]; |
167 | } |
168 | |
169 | thresholdIndex = NO_INDEX; |
170 | return false; |
171 | } |
172 | |
173 | |
174 | inline void ThresholdTable::build(const ThresholdStream& stream) |
175 | { |
176 | //Handle the case of an empty stream. |
177 | if(0==stream.size()) |
178 | { |
179 | mPairsSize=0; |
180 | mPairsCapacity=0; |
181 | mHashSize=0; |
182 | mHashCapactiy=0; |
183 | if(mBuffer) PX_FREE(mBuffer); |
184 | mBuffer = NULL; |
185 | return; |
186 | } |
187 | |
188 | //Realloc/resize if necessary. |
189 | const PxU32 pairsCapacity = stream.size(); |
190 | const PxU32 hashCapacity = pairsCapacity*2+1; |
191 | if((pairsCapacity > mPairsCapacity) || (pairsCapacity < (mPairsCapacity >> 2))) |
192 | { |
193 | if(mBuffer) PX_FREE(mBuffer); |
194 | const PxU32 pairsByteSize = sizeof(Pair)*pairsCapacity; |
195 | const PxU32 nextsByteSize = sizeof(PxU32)*pairsCapacity; |
196 | const PxU32 hashByteSize = sizeof(PxU32)*hashCapacity; |
197 | const PxU32 totalByteSize = pairsByteSize + nextsByteSize + hashByteSize; |
198 | mBuffer = reinterpret_cast<PxU8*>(PX_ALLOC(totalByteSize, "PxThresholdStream" )); |
199 | |
200 | PxU32 offset = 0; |
201 | mPairs = reinterpret_cast<Pair*>(mBuffer + offset); |
202 | offset += pairsByteSize; |
203 | mNexts = reinterpret_cast<PxU32*>(mBuffer + offset); |
204 | offset += nextsByteSize; |
205 | mHash = reinterpret_cast<PxU32*>(mBuffer + offset); |
206 | offset += hashByteSize; |
207 | PX_ASSERT(totalByteSize == offset); |
208 | |
209 | mPairsCapacity = pairsCapacity; |
210 | mHashCapactiy = hashCapacity; |
211 | } |
212 | |
213 | |
214 | //Set each entry of the hash table to 0xffffffff |
215 | PxMemSet(dest: mHash, c: 0xff, count: sizeof(PxU32)*hashCapacity); |
216 | |
217 | //Init the sizes of the pairs array and hash array. |
218 | mPairsSize = 0; |
219 | mHashSize = hashCapacity; |
220 | |
221 | PxU32* PX_RESTRICT hashes = mHash; |
222 | PxU32* PX_RESTRICT nextIndices = mNexts; |
223 | Pair* PX_RESTRICT pairs = mPairs; |
224 | |
225 | //Add all the pairs from the stream. |
226 | PxU32 = 0; |
227 | for(PxU32 i = 0; i < pairsCapacity; i++) |
228 | { |
229 | const ThresholdStreamElement& element = stream[i]; |
230 | const IG::NodeIndex nodeIndexA = element.nodeIndexA; |
231 | const IG::NodeIndex nodeIndexB = element.nodeIndexB; |
232 | |
233 | const PxF32 force = element.normalForce; |
234 | |
235 | PX_ASSERT(nodeIndexA < nodeIndexB); |
236 | |
237 | const PxU32 hashKey = computeHashKey(nodeIndexA: nodeIndexA.index(), nodeIndexB: nodeIndexB.index(), hashCapacity); |
238 | |
239 | //Get the index of the first pair found that resulted in a hash that matched hashKey. |
240 | PxU32 prevPairIndex = hashKey; |
241 | PxU32 pairIndex = hashes[hashKey]; |
242 | |
243 | //Search through all pairs found that resulted in a hash that matched hashKey. |
244 | //Search until the exact same body pair is found. |
245 | //Increment the accumulated force if the exact same body pair is found. |
246 | while(NO_INDEX != pairIndex) |
247 | { |
248 | Pair& pair = pairs[pairIndex]; |
249 | const PxU32 thresholdStreamIndex = pair.thresholdStreamIndex; |
250 | PX_ASSERT(thresholdStreamIndex < stream.size()); |
251 | const ThresholdStreamElement& otherElement = stream[thresholdStreamIndex]; |
252 | if(nodeIndexA == otherElement.nodeIndexA && nodeIndexB==otherElement.nodeIndexB) |
253 | { |
254 | pair.accumulatedForce += force; |
255 | prevPairIndex = NO_INDEX; |
256 | pairIndex = NO_INDEX; |
257 | break; |
258 | } |
259 | prevPairIndex = pairIndex; |
260 | pairIndex = nextIndices[pairIndex]; |
261 | } |
262 | |
263 | if(NO_INDEX != prevPairIndex) |
264 | { |
265 | nextIndices[pairsSize] = hashes[hashKey]; |
266 | hashes[hashKey] = pairsSize; |
267 | Pair& newPair = pairs[pairsSize]; |
268 | newPair.thresholdStreamIndex = i; |
269 | newPair.accumulatedForce = force; |
270 | pairsSize++; |
271 | } |
272 | } |
273 | mPairsSize = pairsSize; |
274 | } |
275 | |
276 | } |
277 | |
278 | } |
279 | |
280 | #endif //DY_THRESHOLDTABLE_H |
281 | |