diff --git a/Extras/BulletMultiThreaded/SpuBatchRaycaster.cpp b/Extras/BulletMultiThreaded/SpuBatchRaycaster.cpp new file mode 100644 index 000000000..d03944a26 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuBatchRaycaster.cpp @@ -0,0 +1,84 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include "SpuBatchRaycaster.h" + +SpuBatchRaycaster::SpuBatchRaycaster (class btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks, btCollisionObjectArray& castUponObjects, int numCastUponObjects) +{ + numCastUponObjectWrappers = numCastUponObjects; + m_threadInterface = threadInterface; + + castUponObjectWrappers = new SpuCollisionObjectWrapper[numCastUponObjects]; + + for (int i = 0; i < numCastUponObjectWrappers; i++) + { + new (&castUponObjectWrappers[i]) SpuCollisionObjectWrapper(castUponObjects[i]); + } + + m_spuRaycastTaskProcess = new SpuRaycastTaskProcess(m_threadInterface,maxNumOutstandingTasks); // FIXME non constant +} + +SpuBatchRaycaster::~SpuBatchRaycaster () +{ +} + +void +SpuBatchRaycaster::addRay (const btVector3& rayFrom, const btVector3& rayTo) +{ + SpuRaycastTaskWorkUnitOut workUnitOut; + workUnitOut.hitFraction = 0.99; + workUnitOut.hitNormal = btVector3(0.0, 1.0, 0.0); + + rayBatchOutput.push_back (workUnitOut); + + SpuRaycastTaskWorkUnit workUnit; + workUnit.rayFrom = rayFrom; + workUnit.rayTo = rayTo; + rayBatch.push_back (workUnit); +} + +void +SpuBatchRaycaster::clearRays () +{ + rayBatch.clear (); + rayBatchOutput.clear (); +} + +void +SpuBatchRaycaster::performBatchRaycast () +{ + m_spuRaycastTaskProcess->initialize2 (castUponObjectWrappers, numCastUponObjectWrappers); + + for (int i = 0; i < rayBatch.size(); i++) + { + rayBatch[i].output = &rayBatchOutput[i]; // assign output memory location + m_spuRaycastTaskProcess->addWorkToTask(rayBatch[i]); + } + + m_spuRaycastTaskProcess->flush2 (); +} + +const SpuRaycastTaskWorkUnitOut& +SpuBatchRaycaster::operator [] (int i) const +{ + return rayBatchOutput[i]; +} + +int +SpuBatchRaycaster::getNumRays () const +{ + return rayBatchOutput.size(); +} \ No newline at end of file diff --git a/Extras/BulletMultiThreaded/SpuBatchRaycaster.h b/Extras/BulletMultiThreaded/SpuBatchRaycaster.h new file mode 100644 index 000000000..177fa5446 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuBatchRaycaster.h @@ -0,0 +1,47 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPU_BATCH_RAYCASTER_H +#define SPU_BATCH_RAYCASTER_H + +#include "LinearMath/btAlignedObjectArray.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "SpuRaycastTaskProcess.h" +#include "SpuRaycastTask/SpuRaycastTask.h" +#include "SpuCollisionObjectWrapper.h" + +/* FIXME: + * Need to decide how callbacks are performed... + */ +class SpuBatchRaycaster +{ +protected: + SpuCollisionObjectWrapper* castUponObjectWrappers; + int numCastUponObjectWrappers; + btAlignedObjectArray rayBatch; + btAlignedObjectArray rayBatchOutput; + SpuRaycastTaskProcess* m_spuRaycastTaskProcess; + class btThreadSupportInterface* m_threadInterface; +public: + SpuBatchRaycaster (class btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks, btCollisionObjectArray& castUponObjects, int numCastUponObjects); + ~SpuBatchRaycaster (); + void addRay (const btVector3& rayFrom, const btVector3& rayTo); + void clearRays (); + void performBatchRaycast (); + const SpuRaycastTaskWorkUnitOut& operator [] (int i) const; + int getNumRays () const; +}; + +#endif diff --git a/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp b/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp new file mode 100644 index 000000000..182aa2694 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp @@ -0,0 +1,48 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SpuCollisionObjectWrapper.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" + +SpuCollisionObjectWrapper::SpuCollisionObjectWrapper () +{ +} + +#ifndef __SPU__ +SpuCollisionObjectWrapper::SpuCollisionObjectWrapper (const btCollisionObject* collisionObject) +{ + m_shapeType = collisionObject->getCollisionShape()->getShapeType (); + m_collisionObjectPtr = (ppu_address_t)collisionObject; + m_margin = collisionObject->getCollisionShape()->getMargin (); +} +#endif + +int +SpuCollisionObjectWrapper::getShapeType () const +{ + return m_shapeType; +} + +float +SpuCollisionObjectWrapper::getCollisionMargin () const +{ + return m_margin; +} + +ppu_address_t +SpuCollisionObjectWrapper::getCollisionObjectPtr () const +{ + return m_collisionObjectPtr; +} diff --git a/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.h b/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.h new file mode 100644 index 000000000..3b069a34a --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuCollisionObjectWrapper.h @@ -0,0 +1,35 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "PlatformDefinitions.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + +class SpuCollisionObjectWrapper +{ +protected: + int m_shapeType; + float m_margin; + ppu_address_t m_collisionObjectPtr; + +public: + SpuCollisionObjectWrapper (); + + SpuCollisionObjectWrapper (const btCollisionObject* collisionObject); + + int getShapeType () const; + float getCollisionMargin () const; + ppu_address_t getCollisionObjectPtr () const; +}; + diff --git a/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp b/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp new file mode 100644 index 000000000..344e5c9c0 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp @@ -0,0 +1,464 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SpuCollisionShapes.h" + +btPoint3 localGetSupportingVertexWithoutMargin(int shapeType, void* shape, btVector3& localDir,struct SpuConvexPolyhedronVertexData* convexVertexData)//, int *featureIndex) +{ + switch (shapeType) + { + case SPHERE_SHAPE_PROXYTYPE: + { + return btPoint3(0,0,0); + } + case BOX_SHAPE_PROXYTYPE: + { +// spu_printf("SPU: getSupport BOX_SHAPE_PROXYTYPE\n"); + btConvexInternalShape* convexShape = (btConvexInternalShape*)shape; + const btVector3& halfExtents = convexShape->getImplicitShapeDimensions(); + + return btPoint3( + localDir.getX() < 0.0f ? -halfExtents.x() : halfExtents.x(), + localDir.getY() < 0.0f ? -halfExtents.y() : halfExtents.y(), + localDir.getZ() < 0.0f ? -halfExtents.z() : halfExtents.z()); + } + + case TRIANGLE_SHAPE_PROXYTYPE: + { + + btVector3 dir(localDir.getX(),localDir.getY(),localDir.getZ()); + btVector3* vertices = (btVector3*)shape; + btVector3 dots(dir.dot(vertices[0]), dir.dot(vertices[1]), dir.dot(vertices[2])); + btVector3 sup = vertices[dots.maxAxis()]; + return btPoint3(sup.getX(),sup.getY(),sup.getZ()); + break; + } + + case CYLINDER_SHAPE_PROXYTYPE: + { + btCylinderShape* cylShape = (btCylinderShape*)shape; + + //mapping of halfextents/dimension onto radius/height depends on how cylinder local orientation is (upAxis) + + btVector3 halfExtents = cylShape->getImplicitShapeDimensions(); + btVector3 v(localDir.getX(),localDir.getY(),localDir.getZ()); + + int cylinderUpAxis = cylShape->getUpAxis(); + int XX(1),YY(0),ZZ(2); + + switch (cylinderUpAxis) + { + case 0: + { + XX = 1; + YY = 0; + ZZ = 2; + break; + } + case 1: + { + XX = 0; + YY = 1; + ZZ = 2; + break; + } + case 2: + { + XX = 0; + YY = 2; + ZZ = 1; + break; + } + default: + btAssert(0); + //printf("SPU:localGetSupportingVertexWithoutMargin unknown Cylinder up-axis\n"); + }; + + btScalar radius = halfExtents[XX]; + btScalar halfHeight = halfExtents[cylinderUpAxis]; + + btVector3 tmp; + btScalar d ; + + btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); + if (s != btScalar(0.0)) + { + d = radius / s; + tmp[XX] = v[XX] * d; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = v[ZZ] * d; + return btPoint3(tmp.getX(),tmp.getY(),tmp.getZ()); + } + else + { + tmp[XX] = radius; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = btScalar(0.0); + return btPoint3(tmp.getX(),tmp.getY(),tmp.getZ()); + } + } + + case CAPSULE_SHAPE_PROXYTYPE: + { + //spu_printf("SPU: todo: getSupport CAPSULE_SHAPE_PROXYTYPE\n"); + btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ()); + + btConvexInternalShape* cnvxShape = (btConvexInternalShape*)shape; + btVector3 halfExtents = cnvxShape->getImplicitShapeDimensions(); + btScalar halfHeight = halfExtents.getY(); + btScalar radius = halfExtents.getX(); + btVector3 supVec(0,0,0); + + btScalar maxDot(btScalar(-1e30)); + + btVector3 vec = vec0; + btScalar lenSqr = vec.length2(); + if (lenSqr < btScalar(0.0001)) + { + vec.setValue(1,0,0); + } else + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + vec *= rlen; + } + btVector3 vtx; + btScalar newDot; + { + btVector3 pos(0,halfHeight,0); + vtx = pos +vec*(radius); + newDot = vec.dot(vtx); + if (newDot > maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + { + btVector3 pos(0,-halfHeight,0); + vtx = pos +vec*(radius); + newDot = vec.dot(vtx); + if (newDot > maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + return btPoint3(supVec.getX(),supVec.getY(),supVec.getZ()); + break; + }; + + case CONVEX_HULL_SHAPE_PROXYTYPE: + { + //spu_printf("SPU: todo: getSupport CONVEX_HULL_SHAPE_PROXYTYPE\n"); + + + + btPoint3* points = 0; + int numPoints = 0; + points = convexVertexData->gConvexPoints; + numPoints = convexVertexData->gNumConvexPoints; + + // spu_printf("numPoints = %d\n",numPoints); + + btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); + btScalar newDot,maxDot = btScalar(-1e30); + + btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ()); + btVector3 vec = vec0; + btScalar lenSqr = vec.length2(); + if (lenSqr < btScalar(0.0001)) + { + vec.setValue(1,0,0); + } else + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + vec *= rlen; + } + + + for (int i=0;i maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + return btPoint3(supVec.getX(),supVec.getY(),supVec.getZ()); + + break; + }; + + default: + + //spu_printf("SPU:(type %i) missing support function\n",shapeType); + + +#if __ASSERT + spu_printf("localGetSupportingVertexWithoutMargin() - Unsupported bound type: %d.\n", shapeType); +#endif // __ASSERT + return btPoint3(0.f, 0.f, 0.f); + } +} + +void computeAabb (btVector3& aabbMin, btVector3& aabbMax, btConvexInternalShape* convexShape, ppu_address_t convexShapePtr, int shapeType, btTransform xform) +{ + //calculate the aabb, given the types... + switch (shapeType) + { + case CYLINDER_SHAPE_PROXYTYPE: + /* fall through */ + case BOX_SHAPE_PROXYTYPE: + { + float margin=convexShape->getMarginNV(); + btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); + btTransform& t = xform; + btMatrix3x3 abs_b = t.getBasis().absolute(); + btPoint3 center = t.getOrigin(); + btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); + extent += btVector3(margin,margin,margin); + aabbMin = center - extent; + aabbMax = center + extent; + break; + } + case CAPSULE_SHAPE_PROXYTYPE: + { + float margin=convexShape->getMarginNV(); + btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); + //add the radius to y-axis to get full height + btScalar radius = halfExtents[0]; + halfExtents[1] += radius; + btTransform& t = xform; + btMatrix3x3 abs_b = t.getBasis().absolute(); + btPoint3 center = t.getOrigin(); + btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); + extent += btVector3(margin,margin,margin); + aabbMin = center - extent; + aabbMax = center + extent; + break; + } + case SPHERE_SHAPE_PROXYTYPE: + { + float radius = convexShape->getImplicitShapeDimensions().getX();// * convexShape->getLocalScaling().getX(); + float margin = radius + convexShape->getMarginNV(); + btTransform& t = xform; + const btVector3& center = t.getOrigin(); + btVector3 extent(margin,margin,margin); + aabbMin = center - extent; + aabbMax = center + extent; + break; + } + case CONVEX_HULL_SHAPE_PROXYTYPE: + { + ATTRIBUTE_ALIGNED16(char convexHullShape0[sizeof(btConvexHullShape)]); + cellDmaGet(&convexHullShape0, convexShapePtr , sizeof(btConvexHullShape), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + btConvexHullShape* localPtr = (btConvexHullShape*)&convexHullShape0; + btTransform& t = xform; + btScalar margin = convexShape->getMarginNV(); + localPtr->getNonvirtualAabb(t,aabbMin,aabbMax,margin); + //spu_printf("SPU convex aabbMin=%f,%f,%f=\n",aabbMin.getX(),aabbMin.getY(),aabbMin.getZ()); + //spu_printf("SPU convex aabbMax=%f,%f,%f=\n",aabbMax.getX(),aabbMax.getY(),aabbMax.getZ()); + break; + } + default: + spu_printf("SPU: unsupported shapetype %d in AABB calculation\n"); + }; +} + +void dmaBvhShapeData (bvhMeshShape_LocalStoreMemory* bvhMeshShape, btBvhTriangleMeshShape* triMeshShape) +{ + register int dmaSize; + register ppu_address_t dmaPpuAddress2; + + dmaSize = sizeof(btTriangleIndexVertexArray); + dmaPpuAddress2 = reinterpret_cast(triMeshShape->getMeshInterface()); + // spu_printf("trimeshShape->getMeshInterface() == %llx\n",dmaPpuAddress2); + bvhMeshShape->gTriangleMeshInterfacePtr = (btTriangleIndexVertexArray*)cellDmaGetReadOnly(&bvhMeshShape->gTriangleMeshInterfaceStorage, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); + //cellDmaWaitTagStatusAll(DMA_MASK(1)); + + ///now DMA over the BVH + + dmaSize = sizeof(btOptimizedBvh); + dmaPpuAddress2 = reinterpret_cast(triMeshShape->getOptimizedBvh()); + //spu_printf("trimeshShape->getOptimizedBvh() == %llx\n",dmaPpuAddress2); + cellDmaGet(&bvhMeshShape->gOptimizedBvh, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0); + //cellDmaWaitTagStatusAll(DMA_MASK(2)); + cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); +} + +void dmaBvhIndexedMesh (btIndexedMesh* IndexMesh, IndexedMeshArray& indexArray, int index, uint32_t dmaTag) +{ + cellDmaGet(IndexMesh, (ppu_address_t)&indexArray[index] , sizeof(btIndexedMesh), DMA_TAG(dmaTag), 0, 0); + +} + +void dmaBvhSubTreeHeaders (btBvhSubtreeInfo* subTreeHeaders, ppu_address_t subTreePtr, int batchSize, uint32_t dmaTag) +{ + cellDmaGet(subTreeHeaders, subTreePtr, batchSize * sizeof(btBvhSubtreeInfo), DMA_TAG(dmaTag), 0, 0); +} + +void dmaBvhSubTreeNodes (btQuantizedBvhNode* nodes, const btBvhSubtreeInfo& subtree, QuantizedNodeArray& nodeArray, int dmaTag) +{ + cellDmaGet(nodes, reinterpret_cast(&nodeArray[subtree.m_rootNodeIndex]) , subtree.m_subtreeSize* sizeof(btQuantizedBvhNode), DMA_TAG(2), 0, 0); +} + +///getShapeTypeSize could easily be optimized, but it is not likely a bottleneck +int getShapeTypeSize(int shapeType) +{ + + + switch (shapeType) + { + case CYLINDER_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btCylinderShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + case BOX_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btBoxShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + case SPHERE_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btSphereShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + case TRIANGLE_MESH_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btBvhTriangleMeshShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + case CAPSULE_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btCapsuleShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + + case CONVEX_HULL_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btConvexHullShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + + case COMPOUND_SHAPE_PROXYTYPE: + { + int shapeSize = sizeof(btCompoundShape); + btAssert(shapeSize < MAX_SHAPE_SIZE); + return shapeSize; + } + + default: + btAssert(0); + //unsupported shapetype, please add here + return 0; + } +} + +void dmaConvexVertexData (SpuConvexPolyhedronVertexData* convexVertexData, btConvexHullShape* convexShapeSPU) +{ + convexVertexData->gNumConvexPoints = convexShapeSPU->getNumPoints(); + if (convexVertexData->gNumConvexPoints>MAX_NUM_SPU_CONVEX_POINTS) + { + btAssert(0); + spu_printf("SPU: Error: MAX_NUM_SPU_CONVEX_POINTS(%d) exceeded: %d\n",MAX_NUM_SPU_CONVEX_POINTS,convexVertexData->gNumConvexPoints); + return; + } + + register int dmaSize = convexVertexData->gNumConvexPoints*sizeof(btPoint3); + ppu_address_t pointsPPU = (ppu_address_t) convexShapeSPU->getPoints(); + cellDmaGet(&convexVertexData->g_convexPointBuffer[0], pointsPPU , dmaSize, DMA_TAG(2), 0, 0); + +} + +void dmaCollisionShape (void* collisionShapeLocation, ppu_address_t collisionShapePtr, uint32_t dmaTag, int shapeType) +{ + register int dmaSize = getShapeTypeSize(shapeType); + cellDmaGet(collisionShapeLocation, collisionShapePtr , dmaSize, DMA_TAG(dmaTag), 0, 0); + //cellDmaWaitTagStatusAll(DMA_MASK(dmaTag)); +} + +void dmaCompoundShapeInfo (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag) +{ + register int dmaSize; + register ppu_address_t dmaPpuAddress2; + int childShapeCount = spuCompoundShape->getNumChildShapes(); + dmaSize = childShapeCount * sizeof(btCompoundShapeChild); + dmaPpuAddress2 = (ppu_address_t)spuCompoundShape->getChildList(); + cellDmaGet(&compoundShapeLocation->gSubshapes[0], dmaPpuAddress2, dmaSize, DMA_TAG(dmaTag), 0, 0); +} + +void dmaCompoundSubShapes (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag) +{ + int childShapeCount = spuCompoundShape->getNumChildShapes(); + int i; + // DMA all the subshapes + for ( i = 0; i < childShapeCount; ++i) + { + btCompoundShapeChild& childShape = compoundShapeLocation->gSubshapes[i]; + dmaCollisionShape (&compoundShapeLocation->gSubshapeShape[i],(ppu_address_t)childShape.m_childShape, dmaTag, childShape.m_childShapeType); + } +} + +void spuWalkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,const btQuantizedBvhNode* rootNode,int startNodeIndex,int endNodeIndex) +{ + + int curIndex = startNodeIndex; + int walkIterations = 0; + int subTreeSize = endNodeIndex - startNodeIndex; + + int escapeIndex; + + unsigned int aabbOverlap, isLeafNode; + + while (curIndex < endNodeIndex) + { + //catch bugs in tree data + assert (walkIterations < subTreeSize); + + walkIterations++; + aabbOverlap = spuTestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); + isLeafNode = rootNode->isLeafNode(); + + if (isLeafNode && aabbOverlap) + { + //printf("overlap with node %d\n",rootNode->getTriangleIndex()); + nodeCallback->processNode(0,rootNode->getTriangleIndex()); + // spu_printf("SPU: overlap detected with triangleIndex:%d\n",rootNode->getTriangleIndex()); + } + + if (aabbOverlap || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->getEscapeIndex(); + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + +} diff --git a/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h b/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h new file mode 100644 index 000000000..6115a18b8 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h @@ -0,0 +1,103 @@ +#ifndef __SPU_COLLISION_SHAPES_H +#define __SPU_COLLISION_SHAPES_H + +#include "../SpuDoubleBuffer.h" + +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "BulletCollision/CollisionShapes/btConvexInternalShape.h" +#include "BulletCollision/CollisionShapes/btCylinderShape.h" + +#include "BulletCollision/CollisionShapes/btOptimizedBvh.h" +#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + +#include "BulletCollision/CollisionShapes/btCapsuleShape.h" + +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btConvexHullShape.h" +#include "BulletCollision/CollisionShapes/btCompoundShape.h" + +#define MAX_NUM_SPU_CONVEX_POINTS 128 + +struct SpuConvexPolyhedronVertexData +{ + void* gSpuConvexShapePtr; + btPoint3* gConvexPoints; + int gNumConvexPoints; + ATTRIBUTE_ALIGNED16(btPoint3 g_convexPointBuffer[MAX_NUM_SPU_CONVEX_POINTS]); +}; + +#define MAX_SHAPE_SIZE 256 + +struct CollisionShape_LocalStoreMemory +{ + ATTRIBUTE_ALIGNED16(char collisionShape[MAX_SHAPE_SIZE]); +}; + +struct CompoundShape_LocalStoreMemory +{ + // Compound data +#define MAX_SPU_COMPOUND_SUBSHAPES 16 + ATTRIBUTE_ALIGNED16(btCompoundShapeChild gSubshapes[MAX_SPU_COMPOUND_SUBSHAPES]); + ATTRIBUTE_ALIGNED16(char gSubshapeShape[MAX_SPU_COMPOUND_SUBSHAPES][MAX_SHAPE_SIZE]); +}; + +struct bvhMeshShape_LocalStoreMemory +{ + //ATTRIBUTE_ALIGNED16(btOptimizedBvh gOptimizedBvh); + ATTRIBUTE_ALIGNED16(char gOptimizedBvh[sizeof(btOptimizedBvh)+16]); + btOptimizedBvh* getOptimizedBvh() + { + return (btOptimizedBvh*) gOptimizedBvh; + } + + ATTRIBUTE_ALIGNED16(btTriangleIndexVertexArray gTriangleMeshInterfaceStorage); + btTriangleIndexVertexArray* gTriangleMeshInterfacePtr; + ///only a single mesh part for now, we can add support for multiple parts, but quantized trees don't support this at the moment + ATTRIBUTE_ALIGNED16(btIndexedMesh gIndexMesh); + #define MAX_SPU_SUBTREE_HEADERS 32 + //1024 + ATTRIBUTE_ALIGNED16(btBvhSubtreeInfo gSubtreeHeaders[MAX_SPU_SUBTREE_HEADERS]); + ATTRIBUTE_ALIGNED16(btQuantizedBvhNode gSubtreeNodes[MAX_SUBTREE_SIZE_IN_BYTES/sizeof(btQuantizedBvhNode)]); +}; + + + +btPoint3 localGetSupportingVertexWithoutMargin(int shapeType, void* shape, btVector3& localDir,struct SpuConvexPolyhedronVertexData* convexVertexData);//, int *featureIndex) +void computeAabb (btVector3& aabbMin, btVector3& aabbMax, btConvexInternalShape* convexShape, ppu_address_t convexShapePtr, int shapeType, btTransform xform); +void dmaBvhShapeData (bvhMeshShape_LocalStoreMemory* bvhMeshShape, btBvhTriangleMeshShape* triMeshShape); +void dmaBvhIndexedMesh (btIndexedMesh* IndexMesh, IndexedMeshArray& indexArray, int index, uint32_t dmaTag); +void dmaBvhSubTreeHeaders (btBvhSubtreeInfo* subTreeHeaders, ppu_address_t subTreePtr, int batchSize, uint32_t dmaTag); +void dmaBvhSubTreeNodes (btQuantizedBvhNode* nodes, const btBvhSubtreeInfo& subtree, QuantizedNodeArray& nodeArray, int dmaTag); + +int getShapeTypeSize(int shapeType); +void dmaConvexVertexData (SpuConvexPolyhedronVertexData* convexVertexData, btConvexHullShape* convexShapeSPU); +void dmaCollisionShape (void* collisionShapeLocation, ppu_address_t collisionShapePtr, uint32_t dmaTag, int shapeType); +void dmaCompoundShapeInfo (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag); +void dmaCompoundSubShapes (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag); + +#define USE_BRANCHFREE_TEST 1 +#ifdef USE_BRANCHFREE_TEST +SIMD_FORCE_INLINE unsigned int spuTestQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) +{ + return btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0]) + & (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2]) + & (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])), + 1, 0); +} +#else + +unsigned int spuTestQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) +{ + unsigned int overlap = 1; + overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? 0 : overlap; + overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? 0 : overlap; + overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? 0 : overlap; + return overlap; +} +#endif + +void spuWalkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,const btQuantizedBvhNode* rootNode,int startNodeIndex,int endNodeIndex); + +#endif diff --git a/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.cpp b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.cpp new file mode 100644 index 000000000..f7c1d7dad --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.cpp @@ -0,0 +1,118 @@ +#include + +#include "SpuRaycastTask.h" +#include "SpuCollisionObjectWrapper.h" +#include "SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h" + + + +struct RaycastTask_LocalStoreMemory +{ + ATTRIBUTE_ALIGNED16(char gColObj [sizeof(btCollisionObject)+16]); + btCollisionObject* getColObj() + { + return (btCollisionObject*) gColObj; + } + + SpuCollisionObjectWrapper gCollisionObjectWrapper; + SpuCollisionObjectWrapper* getCollisionObjectWrapper () + { + return &gCollisionObjectWrapper; + } + + CollisionShape_LocalStoreMemory gCollisionShape; + ATTRIBUTE_ALIGNED16(int spuIndices[16]); + + bvhMeshShape_LocalStoreMemory bvhShapeData; + SpuConvexPolyhedronVertexData convexVertexData; + CompoundShape_LocalStoreMemory compoundShapeData; +}; + +#ifdef WIN32 +void* createRaycastLocalStoreMemory() +{ + return new RaycastTask_LocalStoreMemory; +}; +#elif defined(__CELLOS_LV2__) +ATTRIBUTE_ALIGNED16(RaycastTask_LocalStoreMemory gLocalStoreMemory); +void* createRaycastLocalStoreMemory() +{ + return &gLocalStoreMemory; +} +#endif + +void GatherCollisionObjectAndShapeData (RaycastGatheredObjectData& gatheredObjectData, RaycastTask_LocalStoreMemory& lsMem, ppu_address_t objectWrapper) +{ + register int dmaSize; + register ppu_address_t dmaPpuAddress2; + + /* DMA Collision object wrapper into local store */ + dmaSize = sizeof(SpuCollisionObjectWrapper); + dmaPpuAddress2 = objectWrapper; + cellDmaGet(&lsMem.gCollisionObjectWrapper, dmaPpuAddress2, dmaSize, DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + /* DMA Collision object into local store */ + dmaSize = sizeof(btCollisionObject); + dmaPpuAddress2 = lsMem.getCollisionObjectWrapper()->getCollisionObjectPtr(); + cellDmaGet(&lsMem.gColObj, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(2)); + + /* Gather information about collision object and shape */ + gatheredObjectData.m_worldTransform = lsMem.getColObj()->getWorldTransform(); + gatheredObjectData.m_collisionMargin = lsMem.getCollisionObjectWrapper()->getCollisionMargin (); + gatheredObjectData.m_shapeType = lsMem.getCollisionObjectWrapper()->getShapeType (); + gatheredObjectData.m_collisionShape = (ppu_address_t)lsMem.getColObj()->getCollisionShape(); + gatheredObjectData.m_spuCollisionShape = (void*)&lsMem.gCollisionShape.collisionShape[0]; + + /* DMA shape data */ + dmaCollisionShape (gatheredObjectData.m_spuCollisionShape, gatheredObjectData.m_collisionShape, 1, gatheredObjectData.m_shapeType); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + btConvexInternalShape* spuConvexShape = (btConvexInternalShape*)gatheredObjectData.m_spuCollisionShape; + gatheredObjectData.m_primitiveDimensions = spuConvexShape->getImplicitShapeDimensions (); +} + +void dmaLoadRayOutput (ppu_address_t rayOutputAddr, SpuRaycastTaskWorkUnitOut* rayOutput, uint32_t dmaTag) +{ + cellDmaGet(rayOutput, rayOutputAddr, sizeof(*rayOutput), DMA_TAG(dmaTag), 0, 0); +} + +void dmaStoreRayOutput (ppu_address_t rayOutputAddr, const SpuRaycastTaskWorkUnitOut* rayOutput, uint32_t dmaTag) +{ + cellDmaLargePut (rayOutput, rayOutputAddr, sizeof(*rayOutput), DMA_TAG(dmaTag), 0, 0); +} + +void processRaycastTask(void* userPtr, void* lsMemory) +{ + RaycastTask_LocalStoreMemory* localMemory = (RaycastTask_LocalStoreMemory*)lsMemory; + + SpuRaycastTaskDesc* taskDescPtr = (SpuRaycastTaskDesc*)userPtr; + SpuRaycastTaskDesc& taskDesc = *taskDescPtr; + + SpuCollisionObjectWrapper* cows = (SpuCollisionObjectWrapper*)taskDesc.spuCollisionObjectsWrappers; + + /* for each object */ + for (int objectId = 0; objectId < taskDesc.numSpuCollisionObjectWrappers; objectId++) + { + RaycastGatheredObjectData gatheredObjectData; + GatherCollisionObjectAndShapeData (gatheredObjectData, *localMemory, (ppu_address_t)&cows[objectId]); + /* load initial collision shape */ + for (int rayId = 0; rayId < taskDesc.numWorkUnits; rayId++) + { + SpuRaycastTaskWorkUnitOut rayOut; + + dmaLoadRayOutput ((ppu_address_t)taskDesc.workUnits[rayId].output, &rayOut, 1); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + float t = (float)rayId/(float)taskDesc.numWorkUnits; + /* performRaycast */ + rayOut.hitFraction = 0.1f * t; + rayOut.hitNormal = btVector3(1.0, 0.0, 0.0); + + /* write ray cast data back */ + dmaStoreRayOutput ((ppu_address_t)taskDesc.workUnits[rayId].output, &rayOut, 1); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + } + } + +} diff --git a/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.h b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.h new file mode 100644 index 000000000..0eb1b5d8b --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuRaycastTask.h @@ -0,0 +1,48 @@ +#ifndef __SPU_RAYCAST_TASK_H +#define __SPU_RAYCAST_TASK_H + +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" +#include "LinearMath/btVector3.h" +#include "PlatformDefinitions.h" + +struct RaycastGatheredObjectData +{ + ppu_address_t m_collisionShape; + void* m_spuCollisionShape; + btVector3 m_primitiveDimensions; + int m_shapeType; + float m_collisionMargin; + btTransform m_worldTransform; +}; + +struct SpuRaycastTaskWorkUnitOut +{ + btVector3 hitNormal; /* out */ + btScalar hitFraction; /* out */ + btCollisionWorld::LocalShapeInfo shapeInfo; /* out */ +}; + +/* Perform a raycast on collision object */ +struct SpuRaycastTaskWorkUnit +{ + btVector3 rayFrom; /* in */ + btVector3 rayTo; /* in */ + SpuRaycastTaskWorkUnitOut* output; /* out */ +}; + +#define SPU_RAYCAST_WORK_UNITS_PER_TASK 16 + +struct SpuRaycastTaskDesc +{ + SpuRaycastTaskWorkUnit workUnits[SPU_RAYCAST_WORK_UNITS_PER_TASK]; + int numWorkUnits; + void* spuCollisionObjectsWrappers; + int numSpuCollisionObjectWrappers; + int taskId; +}; + +void processRaycastTask (void* userPtr, void* lsMemory); +void* createRaycastLocalStoreMemory (); + +#endif diff --git a/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.cpp b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.cpp new file mode 100644 index 000000000..8cb60a770 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.cpp @@ -0,0 +1,145 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "SpuSubSimplexConvexCast.h" +#include "SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h" + +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" + + +SpuSubsimplexConvexCast::SpuSubsimplexConvexCast (const void* convexA, + const void* convexB, + SpuVoronoiSimplexSolver* simplexSolver) + :m_simplexSolver(simplexSolver), m_convexA(convexA),m_convexB(convexB) +{ +} + +///Typically the conservative advancement reaches solution in a few iterations, clip it to 32 for degenerate cases. +///See discussion about this here http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=565 +#ifdef BT_USE_DOUBLE_PRECISION +#define MAX_ITERATIONS 64 +#else +#define MAX_ITERATIONS 32 +#endif + +bool SpuSubsimplexConvexCast::calcTimeOfImpact(const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + SpuCastResult& result) +{ + //localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]); +#if 0 + btMinkowskiSumShape combi(m_convexA,m_convexB); + btMinkowskiSumShape* convex = &combi; + + btTransform rayFromLocalA; + btTransform rayToLocalA; + + rayFromLocalA = fromA.inverse()* fromB; + rayToLocalA = toA.inverse()* toB; + + + m_simplexSolver->reset(); + + convex->setTransformB(btTransform(rayFromLocalA.getBasis())); + + //btScalar radius = btScalar(0.01); + + btScalar lambda = btScalar(0.); + //todo: need to verify this: + //because of minkowski difference, we need the inverse direction + + btVector3 s = -rayFromLocalA.getOrigin(); + btVector3 r = -(rayToLocalA.getOrigin()-rayFromLocalA.getOrigin()); + btVector3 x = s; + btVector3 v; + btVector3 arbitraryPoint = convex->localGetSupportingVertex(r); + + v = x - arbitraryPoint; + + int maxIter = MAX_ITERATIONS; + + btVector3 n; + n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + bool hasResult = false; + btVector3 c; + + btScalar lastLambda = lambda; + + + btScalar dist2 = v.length2(); +#ifdef BT_USE_DOUBLE_PRECISION + btScalar epsilon = btScalar(0.0001); +#else + btScalar epsilon = btScalar(0.0001); +#endif //BT_USE_DOUBLE_PRECISION + btVector3 w,p; + btScalar VdotR; + + while ( (dist2 > epsilon) && maxIter--) + { + p = convex->localGetSupportingVertex( v); + w = x - p; + + btScalar VdotW = v.dot(w); + + if ( VdotW > btScalar(0.)) + { + VdotR = v.dot(r); + + if (VdotR >= -(SIMD_EPSILON*SIMD_EPSILON)) + return false; + else + { + lambda = lambda - VdotW / VdotR; + x = s + lambda * r; + m_simplexSolver->reset(); + //check next line + w = x-p; + lastLambda = lambda; + n = v; + hasResult = true; + } + } + m_simplexSolver->addVertex( w, x , p); + if (m_simplexSolver->closest(v)) + { + dist2 = v.length2(); + hasResult = true; + //printf("V=%f , %f, %f\n",v[0],v[1],v[2]); + //printf("DIST2=%f\n",dist2); + //printf("numverts = %i\n",m_simplexSolver->numVertices()); + } else + { + dist2 = btScalar(0.); + } + } + + //int numiter = MAX_ITERATIONS - maxIter; +// printf("number of iterations: %d", numiter); + result.m_fraction = lambda; + result.m_normal = n; + +#endif + + return true; +} + + + diff --git a/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.h b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.h new file mode 100644 index 000000000..f539722c7 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTask/SpuSubSimplexConvexCast.h @@ -0,0 +1,56 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SPU_SUBSIMPLEX_CONVEX_CAST_H +#define SPU_SUBSIMPLEX_CONVEX_CAST_H + +#include "SpuNarrowPhaseCollisionTask/SpuVoronoiSimplexSolver.h" +#include "SpuRaycastTask.h" + +class btConvexShape; + +struct SpuCastResult +{ +}; + +/// btSubsimplexConvexCast implements Gino van den Bergens' paper +///"Ray Casting against bteral Convex Objects with Application to Continuous Collision Detection" +/// GJK based Ray Cast, optimized version +/// Objects should not start in overlap, otherwise results are not defined. +class SpuSubsimplexConvexCast +{ + SpuVoronoiSimplexSolver* m_simplexSolver; + const void* m_convexA; + const void* m_convexB; + RaycastGatheredObjectData* m_dataB; +public: + + SpuSubsimplexConvexCast (const void* shapeA, + const void* shapeB, + SpuVoronoiSimplexSolver* simplexSolver); + + //virtual ~btSubsimplexConvexCast(); + ///SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (sweep) between two moving objects. + ///Precondition is that objects should not penetration/overlap at the start from the interval. Overlap can be tested using btGjkPairDetector. + bool calcTimeOfImpact(const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + SpuCastResult& result); + +}; + +#endif //SUBSIMPLEX_CONVEX_CAST_H diff --git a/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.cpp b/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.cpp new file mode 100644 index 000000000..9c453d377 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.cpp @@ -0,0 +1,172 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "SpuRaycastTaskProcess.h" + +SpuRaycastTaskProcess::SpuRaycastTaskProcess(class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks) +:m_threadInterface(threadInterface), +m_maxNumOutstandingTasks(maxNumOutstandingTasks) +{ + m_workUnitTaskBuffers = (unsigned char *)0; + m_taskBusy.resize(m_maxNumOutstandingTasks); + m_spuRaycastTaskDesc.resize(m_maxNumOutstandingTasks); + + for (int i = 0; i < m_maxNumOutstandingTasks; i++) + { + m_taskBusy[i] = false; + } + m_numBusyTasks = 0; + m_currentTask = 0; + m_currentWorkUnitInTask = 0; + + m_threadInterface->startSPU(); + + //printf("sizeof vec_float4: %d\n", sizeof(vec_float4)); + //printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", sizeof(SpuGatherAndProcessWorkUnitInput)); + +} + +SpuRaycastTaskProcess::~SpuRaycastTaskProcess() +{ + + if (m_workUnitTaskBuffers != 0) + { + btAlignedFree(m_workUnitTaskBuffers); + m_workUnitTaskBuffers = 0; + } + + m_threadInterface->stopSPU(); +} + + + +void SpuRaycastTaskProcess::initialize2(void* spuCollisionObjectsWrappers, int numSpuCollisionObjectWrappers) +{ + m_spuCollisionObjectWrappers = spuCollisionObjectsWrappers; + m_numSpuCollisionObjectWrappers = numSpuCollisionObjectWrappers; + for (int i = 0; i < m_maxNumOutstandingTasks; i++) + { + m_taskBusy[i] = false; + } + m_numBusyTasks = 0; + m_currentTask = 0; + m_currentWorkUnitInTask = 0; + +#ifdef DEBUG_SpuRaycastTaskProcess + m_initialized = true; +#endif +} + + +void SpuRaycastTaskProcess::issueTask2() +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpuRaycastTaskDesc& taskDesc = m_spuRaycastTaskDesc[m_currentTask]; + + taskDesc.taskId = m_currentTask; + m_threadInterface->sendRequest(1, (uint32_t) &taskDesc,m_currentTask); + //printf("send thread requested for task %d\n", m_currentTask); + // if all tasks busy, wait for spu event to clear the task. + if (m_numBusyTasks >= m_maxNumOutstandingTasks) + { + unsigned int taskId; + unsigned int outputSize; + + m_threadInterface->waitForResponse(&taskId, &outputSize); + + //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize); + + m_taskBusy[taskId] = false; + + m_numBusyTasks--; + } else { + //printf("Sent request, not enough busy tasks\n"); + } +} + +void SpuRaycastTaskProcess::addWorkToTask(SpuRaycastTaskWorkUnit workunit) +{ + m_spuRaycastTaskDesc[m_currentTask].workUnits[m_currentWorkUnitInTask] = workunit; + m_currentWorkUnitInTask++; + if (m_currentWorkUnitInTask == SPU_RAYCAST_WORK_UNITS_PER_TASK) + { + m_spuRaycastTaskDesc[m_currentTask].numWorkUnits = m_currentWorkUnitInTask; + m_spuRaycastTaskDesc[m_currentTask].numSpuCollisionObjectWrappers = m_numSpuCollisionObjectWrappers; + m_spuRaycastTaskDesc[m_currentTask].spuCollisionObjectsWrappers = m_spuCollisionObjectWrappers; + //printf("Task buffer full, issuing\n"); + issueTask2 (); + //printf("Returned from issueTask2()\n"); + m_currentWorkUnitInTask = 0; + + // find new task buffer + for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++) + { + if (!m_taskBusy[i]) + { + m_currentTask = i; + //init the task data + break; + } + } + //printf("next task = %d\n", m_currentTask); + } +} + + +void +SpuRaycastTaskProcess::flush2() +{ +#ifdef DEBUG_SPU_TASK_SCHEDULING + printf("\nSpuRaycastTaskProcess::flush()\n"); +#endif //DEBUG_SPU_TASK_SCHEDULING + + // if there's a partially filled task buffer, submit that task + //printf("Flushing... %d remaining\n", m_currentWorkUnitInTask); + if (m_currentWorkUnitInTask > 0) + { + m_spuRaycastTaskDesc[m_currentTask].numWorkUnits = m_currentWorkUnitInTask; + m_spuRaycastTaskDesc[m_currentTask].numSpuCollisionObjectWrappers = m_numSpuCollisionObjectWrappers; + m_spuRaycastTaskDesc[m_currentTask].spuCollisionObjectsWrappers = m_spuCollisionObjectWrappers; + issueTask2(); + m_currentWorkUnitInTask = 0; + } + + + // all tasks are issued, wait for all tasks to be complete + while(m_numBusyTasks > 0) + { + // Consolidating SPU code + unsigned int taskId; + unsigned int outputSize; + + //printf("Busy tasks... %d\n", m_numBusyTasks); + + { + // SPURS support. + m_threadInterface->waitForResponse(&taskId, &outputSize); + } + + //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize); + + //postProcess(taskId, outputSize); + + m_taskBusy[taskId] = false; + + m_numBusyTasks--; + } +} diff --git a/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.h b/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.h new file mode 100644 index 000000000..42d7f1222 --- /dev/null +++ b/Extras/BulletMultiThreaded/SpuRaycastTaskProcess.h @@ -0,0 +1,72 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPU_RAY_TASK_PROCESS_H +#define SPU_RAY_TASK_PROCESS_H + +#include +#include + +#include +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include + +#include "PlatformDefinitions.h" +#include "LinearMath/btAlignedObjectArray.h" +#include "SpuRaycastTask/SpuRaycastTask.h" + +#include "btThreadSupportInterface.h" + +/// SpuRaycastTaskProcess handles SPU processing of raycast requests +class SpuRaycastTaskProcess +{ + unsigned char *m_workUnitTaskBuffers; + + // track task buffers that are being used, and total busy tasks + btAlignedObjectArray m_taskBusy; + btAlignedObjectArray m_spuRaycastTaskDesc; + + btThreadSupportInterface* m_threadInterface; + + unsigned int m_maxNumOutstandingTasks; + + unsigned int m_numBusyTasks; + + // the current task and the current entry to insert a new work unit + unsigned int m_currentTask; + unsigned int m_currentWorkUnitInTask; + int m_numSpuCollisionObjectWrappers; + void* m_spuCollisionObjectWrappers; + void issueTask2(); + //void postProcess(unsigned int taskId, int outputSize); + +public: + SpuRaycastTaskProcess(btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks); + + ~SpuRaycastTaskProcess(); + + /// call initialize in the beginning of the frame, before addCollisionPairToTask + void initialize2(void* spuCollisionObjectsWrappers, int numSpuCollisionObjectWrappers); + + /// batch up additional work to a current task for SPU processing. When batch is full, it issues the task. + void addWorkToTask(struct SpuRaycastTaskWorkUnit); + + /// call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished + void flush2(); +}; + + +#endif // SPU_COLLISION_TASK_PROCESS_H +