Imported Upstream version 2.81
[platform/upstream/libbullet.git] / src / BulletMultiThreaded / SpuGatheringCollisionDispatcher.cpp
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
16 #include "SpuGatheringCollisionDispatcher.h"
17 #include "SpuCollisionTaskProcess.h"
18
19
20 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
21 #include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
22 #include "SpuContactManifoldCollisionAlgorithm.h"
23 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
24 #include "BulletCollision/CollisionShapes/btCollisionShape.h"
25 #include "LinearMath/btQuickprof.h"
26 #include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h"
27 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
28
29
30
31
32 SpuGatheringCollisionDispatcher::SpuGatheringCollisionDispatcher(class  btThreadSupportInterface*       threadInterface, unsigned int   maxNumOutstandingTasks,btCollisionConfiguration* collisionConfiguration)
33 :btCollisionDispatcher(collisionConfiguration),
34 m_spuCollisionTaskProcess(0),
35 m_threadInterface(threadInterface),
36 m_maxNumOutstandingTasks(maxNumOutstandingTasks)
37 {
38         
39 }
40
41
42 bool    SpuGatheringCollisionDispatcher::supportsDispatchPairOnSpu(int proxyType0,int proxyType1)
43 {
44         bool supported0 = (
45                 (proxyType0 == BOX_SHAPE_PROXYTYPE) ||
46                 (proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) ||
47                 (proxyType0 == SPHERE_SHAPE_PROXYTYPE) ||
48                 (proxyType0 == CAPSULE_SHAPE_PROXYTYPE) ||
49                 (proxyType0 == CYLINDER_SHAPE_PROXYTYPE) ||
50 //              (proxyType0 == CONE_SHAPE_PROXYTYPE) ||
51                 (proxyType0 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
52                 (proxyType0 == CONVEX_HULL_SHAPE_PROXYTYPE)||
53                 (proxyType0 == STATIC_PLANE_PROXYTYPE)||
54                 (proxyType0 == COMPOUND_SHAPE_PROXYTYPE)
55                 );
56
57         bool supported1 = (
58                 (proxyType1 == BOX_SHAPE_PROXYTYPE) ||
59                 (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE) ||
60                 (proxyType1 == SPHERE_SHAPE_PROXYTYPE) ||
61                 (proxyType1 == CAPSULE_SHAPE_PROXYTYPE) ||
62                 (proxyType1 == CYLINDER_SHAPE_PROXYTYPE) ||
63 //              (proxyType1 == CONE_SHAPE_PROXYTYPE) ||
64                 (proxyType1 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
65                 (proxyType1 == CONVEX_HULL_SHAPE_PROXYTYPE) ||
66                 (proxyType1 == STATIC_PLANE_PROXYTYPE) ||
67                 (proxyType1 == COMPOUND_SHAPE_PROXYTYPE)
68                 );
69
70         
71         return supported0 && supported1;
72 }
73
74
75
76 SpuGatheringCollisionDispatcher::~SpuGatheringCollisionDispatcher()
77 {
78         if (m_spuCollisionTaskProcess)
79                 delete m_spuCollisionTaskProcess;
80         
81 }
82
83 #include "stdio.h"
84
85
86
87 ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc)
88 ///this is useful for the collision dispatcher.
89 class btSpuCollisionPairCallback : public btOverlapCallback
90 {
91         const btDispatcherInfo& m_dispatchInfo;
92         SpuGatheringCollisionDispatcher*        m_dispatcher;
93
94 public:
95
96         btSpuCollisionPairCallback(const btDispatcherInfo& dispatchInfo, SpuGatheringCollisionDispatcher*       dispatcher)
97         :m_dispatchInfo(dispatchInfo),
98         m_dispatcher(dispatcher)
99         {
100         }
101
102         virtual bool    processOverlap(btBroadphasePair& collisionPair)
103         {
104
105
106                 //PPU version
107                 //(*m_dispatcher->getNearCallback())(collisionPair,*m_dispatcher,m_dispatchInfo);
108
109                 //only support discrete collision detection for now, we could fallback on PPU/unoptimized version for TOI/CCD
110                 btAssert(m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE);
111
112                 //by default, Bullet will use this near callback
113                 {
114                         ///userInfo is used to determine if the SPU has to handle this case or not (skip PPU tasks)
115                         if (!collisionPair.m_internalTmpValue)
116                         {
117                                 collisionPair.m_internalTmpValue = 1;
118                         }
119                         if (!collisionPair.m_algorithm)
120                         {
121                                 btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
122                                 btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
123
124                                 btCollisionAlgorithmConstructionInfo ci;
125                                 ci.m_dispatcher1 = m_dispatcher;
126                                 ci.m_manifold = 0;
127
128                                 if (m_dispatcher->needsCollision(colObj0,colObj1))
129                                 {
130                                         int     proxyType0 = colObj0->getCollisionShape()->getShapeType();
131                                         int     proxyType1 = colObj1->getCollisionShape()->getShapeType();
132                                         bool supportsSpuDispatch = m_dispatcher->supportsDispatchPairOnSpu(proxyType0,proxyType1) 
133                                                 && ((colObj0->getCollisionFlags() & btCollisionObject::CF_DISABLE_SPU_COLLISION_PROCESSING) == 0)
134                                                 && ((colObj1->getCollisionFlags() & btCollisionObject::CF_DISABLE_SPU_COLLISION_PROCESSING) == 0);
135
136                                         if (proxyType0 == COMPOUND_SHAPE_PROXYTYPE)
137                                         {
138                                                 btCompoundShape* compound = (btCompoundShape*)colObj0->getCollisionShape();
139                                                 if (compound->getNumChildShapes()>MAX_SPU_COMPOUND_SUBSHAPES)
140                                                 {
141                                                         //printf("PPU fallback, compound->getNumChildShapes(%d)>%d\n",compound->getNumChildShapes(),MAX_SPU_COMPOUND_SUBSHAPES);
142                                                         supportsSpuDispatch = false;
143                                                 }
144                                         }
145
146                                         if (proxyType1 == COMPOUND_SHAPE_PROXYTYPE)
147                                         {
148                                                 btCompoundShape* compound = (btCompoundShape*)colObj1->getCollisionShape();
149                                                 if (compound->getNumChildShapes()>MAX_SPU_COMPOUND_SUBSHAPES)
150                                                 {
151                                                         //printf("PPU fallback, compound->getNumChildShapes(%d)>%d\n",compound->getNumChildShapes(),MAX_SPU_COMPOUND_SUBSHAPES);
152                                                         supportsSpuDispatch = false;
153                                                 }
154                                         }
155
156                                         if (supportsSpuDispatch)
157                                         {
158
159                                                 int so = sizeof(SpuContactManifoldCollisionAlgorithm);
160 #ifdef ALLOCATE_SEPARATELY
161                                                 void* mem = btAlignedAlloc(so,16);//m_dispatcher->allocateCollisionAlgorithm(so);
162 #else
163                                                 void* mem = m_dispatcher->allocateCollisionAlgorithm(so);
164 #endif
165                                                 collisionPair.m_algorithm = new(mem) SpuContactManifoldCollisionAlgorithm(ci,colObj0,colObj1);
166                                                 collisionPair.m_internalTmpValue =  2;
167                                         } else
168                                         {
169                                                 btCollisionObjectWrapper ob0(0,colObj0->getCollisionShape(),colObj0,colObj0->getWorldTransform());
170                                                 btCollisionObjectWrapper ob1(0,colObj1->getCollisionShape(),colObj1,colObj1->getWorldTransform());
171
172                                                 collisionPair.m_algorithm = m_dispatcher->findAlgorithm(&ob0,&ob1);
173                                                 collisionPair.m_internalTmpValue = 3;
174                                         }
175                                 } 
176                         }
177                 }
178                 return false;
179         }
180 };
181
182 void    SpuGatheringCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo, btDispatcher* dispatcher) 
183 {
184
185         if (dispatchInfo.m_enableSPU)
186         {
187                 m_maxNumOutstandingTasks = m_threadInterface->getNumTasks();
188
189                 {
190                         BT_PROFILE("processAllOverlappingPairs");
191
192                         if (!m_spuCollisionTaskProcess)
193                                 m_spuCollisionTaskProcess = new SpuCollisionTaskProcess(m_threadInterface,m_maxNumOutstandingTasks);
194                 
195                         m_spuCollisionTaskProcess->setNumTasks(m_maxNumOutstandingTasks);
196         //              printf("m_maxNumOutstandingTasks =%d\n",m_maxNumOutstandingTasks);
197
198                         m_spuCollisionTaskProcess->initialize2(dispatchInfo.m_useEpa);
199                         
200                 
201                         ///modified version of btCollisionDispatcher::dispatchAllCollisionPairs:
202                         {
203                                 btSpuCollisionPairCallback      collisionCallback(dispatchInfo,this);
204
205                                 pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher);
206                         }
207                 }
208
209                 //send one big batch
210                 int numTotalPairs = pairCache->getNumOverlappingPairs();
211                 if (numTotalPairs)
212                 {
213                         btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr();
214                         int i;
215                         {
216                                 int pairRange = SPU_BATCHSIZE_BROADPHASE_PAIRS;
217                                 if (numTotalPairs < (m_spuCollisionTaskProcess->getNumTasks()*SPU_BATCHSIZE_BROADPHASE_PAIRS))
218                                 {
219                                         pairRange = (numTotalPairs/m_spuCollisionTaskProcess->getNumTasks())+1;
220                                 }
221         
222                                 BT_PROFILE("addWorkToTask");
223                                 for (i=0;i<numTotalPairs;)
224                                 {
225                                         //Performance Hint: tweak this number during benchmarking
226                                         
227                                         int endIndex = (i+pairRange) < numTotalPairs ? i+pairRange : numTotalPairs;
228                                         m_spuCollisionTaskProcess->addWorkToTask(pairPtr,i,endIndex);
229                                         i = endIndex;
230                                 }
231                         }
232                         {
233                                 BT_PROFILE("PPU fallback");
234                                 //handle PPU fallback pairs
235                                 for (i=0;i<numTotalPairs;i++)
236                                 {
237                                         btBroadphasePair& collisionPair = pairPtr[i];
238                                         if (collisionPair.m_internalTmpValue == 3)
239                                         {
240                                                 if (collisionPair.m_algorithm)
241                                                 {
242                                                         btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
243                                                         btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
244         
245                                                         if (dispatcher->needsCollision(colObj0,colObj1))
246                                                         {
247                                                         //discrete collision detection query
248                                                                 btCollisionObjectWrapper ob0(0,colObj0->getCollisionShape(),colObj0,colObj0->getWorldTransform());
249                                                                 btCollisionObjectWrapper ob1(0,colObj1->getCollisionShape(),colObj1,colObj1->getWorldTransform());
250
251                                                                 btManifoldResult contactPointResult(&ob0,&ob1);
252                                                                 
253                                                                 if (dispatchInfo.m_dispatchFunc ==              btDispatcherInfo::DISPATCH_DISCRETE)
254                                                                 {
255                                                                         
256                                                                         collisionPair.m_algorithm->processCollision(&ob0,&ob1,dispatchInfo,&contactPointResult);
257                                                                 } else
258                                                                 {
259                                                                         //continuous collision detection query, time of impact (toi)
260                                                                         btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
261                                                                         if (dispatchInfo.m_timeOfImpact > toi)
262                                                                                 dispatchInfo.m_timeOfImpact = toi;
263         
264                                                                 }
265                                                         }
266                                                 }
267                                         }
268                                 }
269                         }
270                 }
271                 {
272                         BT_PROFILE("flush2");
273                         //make sure all SPU work is done
274                         m_spuCollisionTaskProcess->flush2();
275                 }
276
277         } else
278         {
279                 ///PPU fallback
280                 ///!Need to make sure to clear all 'algorithms' when switching between SPU and PPU
281                 btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo,dispatcher);
282         }
283 }