938 lines
27 KiB
C++
938 lines
27 KiB
C++
/*
|
|
Copyright (c) 2012 Advanced Micro Devices, Inc.
|
|
|
|
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.
|
|
*/
|
|
//Originally written by Takahiro Harada
|
|
|
|
|
|
#include "b3Solver.h"
|
|
|
|
///useNewBatchingKernel is a rewritten kernel using just a single thread of the warp, for experiments
|
|
bool useNewBatchingKernel = false;
|
|
|
|
#define SOLVER_SETUP_KERNEL_PATH "opencl/gpu_rigidbody/kernels/solverSetup.cl"
|
|
#define SOLVER_SETUP2_KERNEL_PATH "opencl/gpu_rigidbody/kernels/solverSetup2.cl"
|
|
|
|
#define SOLVER_CONTACT_KERNEL_PATH "opencl/gpu_rigidbody/kernels/solveContact.cl"
|
|
#define SOLVER_FRICTION_KERNEL_PATH "opencl/gpu_rigidbody/kernels/solveFriction.cl"
|
|
|
|
#define BATCHING_PATH "opencl/gpu_rigidbody/kernels/batchingKernels.cl"
|
|
#define BATCHING_NEW_PATH "opencl/gpu_rigidbody/kernels/batchingKernelsNew.cl"
|
|
|
|
|
|
#include "../kernels/solverSetup.h"
|
|
#include "../kernels/solverSetup2.h"
|
|
|
|
#include "../kernels/solveContact.h"
|
|
#include "../kernels/solveFriction.h"
|
|
|
|
#include "../kernels/batchingKernels.h"
|
|
#include "../kernels/batchingKernelsNew.h"
|
|
|
|
|
|
#include "BulletCommon/btQuickprof.h"
|
|
#include "../../parallel_primitives/host/btLauncherCL.h"
|
|
#include "BulletCommon/btVector3.h"
|
|
|
|
struct SolverDebugInfo
|
|
{
|
|
int m_valInt0;
|
|
int m_valInt1;
|
|
int m_valInt2;
|
|
int m_valInt3;
|
|
|
|
int m_valInt4;
|
|
int m_valInt5;
|
|
int m_valInt6;
|
|
int m_valInt7;
|
|
|
|
int m_valInt8;
|
|
int m_valInt9;
|
|
int m_valInt10;
|
|
int m_valInt11;
|
|
|
|
int m_valInt12;
|
|
int m_valInt13;
|
|
int m_valInt14;
|
|
int m_valInt15;
|
|
|
|
|
|
float m_val0;
|
|
float m_val1;
|
|
float m_val2;
|
|
float m_val3;
|
|
};
|
|
|
|
|
|
|
|
|
|
class SolverDeviceInl
|
|
{
|
|
public:
|
|
struct ParallelSolveData
|
|
{
|
|
btOpenCLArray<unsigned int>* m_numConstraints;
|
|
btOpenCLArray<unsigned int>* m_offsets;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
b3Solver::b3Solver(cl_context ctx, cl_device_id device, cl_command_queue queue, int pairCapacity)
|
|
:m_nIterations(4),
|
|
m_context(ctx),
|
|
m_device(device),
|
|
m_queue(queue)
|
|
{
|
|
m_sort32 = new btRadixSort32CL(ctx,device,queue);
|
|
m_scan = new btPrefixScanCL(ctx,device,queue,N_SPLIT*N_SPLIT);
|
|
m_search = new btBoundSearchCL(ctx,device,queue,N_SPLIT*N_SPLIT);
|
|
|
|
const int sortSize = BTNEXTMULTIPLEOF( pairCapacity, 512 );
|
|
|
|
m_sortDataBuffer = new btOpenCLArray<btSortData>(ctx,queue,sortSize);
|
|
m_contactBuffer2 = new btOpenCLArray<b3Contact4>(ctx,queue);
|
|
|
|
m_numConstraints = new btOpenCLArray<unsigned int>(ctx,queue,N_SPLIT*N_SPLIT );
|
|
m_numConstraints->resize(N_SPLIT*N_SPLIT);
|
|
|
|
m_offsets = new btOpenCLArray<unsigned int>( ctx,queue, N_SPLIT*N_SPLIT );
|
|
m_offsets->resize(N_SPLIT*N_SPLIT);
|
|
const char* additionalMacros = "";
|
|
const char* srcFileNameForCaching="";
|
|
|
|
|
|
|
|
cl_int pErrNum;
|
|
const char* batchKernelSource = batchingKernelsCL;
|
|
const char* batchKernelNewSource = batchingKernelsNewCL;
|
|
|
|
const char* solverSetupSource = solverSetupCL;
|
|
const char* solverSetup2Source = solverSetup2CL;
|
|
const char* solveContactSource = solveContactCL;
|
|
const char* solveFrictionSource = solveFrictionCL;
|
|
|
|
|
|
|
|
{
|
|
|
|
cl_program solveContactProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveContactSource, &pErrNum,additionalMacros, SOLVER_CONTACT_KERNEL_PATH);
|
|
btAssert(solveContactProg);
|
|
|
|
cl_program solveFrictionProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveFrictionSource, &pErrNum,additionalMacros, SOLVER_FRICTION_KERNEL_PATH);
|
|
btAssert(solveFrictionProg);
|
|
|
|
cl_program solverSetup2Prog= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetup2Source, &pErrNum,additionalMacros, SOLVER_SETUP2_KERNEL_PATH);
|
|
btAssert(solverSetup2Prog);
|
|
|
|
|
|
cl_program solverSetupProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetupSource, &pErrNum,additionalMacros, SOLVER_SETUP_KERNEL_PATH);
|
|
btAssert(solverSetupProg);
|
|
|
|
|
|
m_solveFrictionKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveFrictionSource, "BatchSolveKernelFriction", &pErrNum, solveFrictionProg,additionalMacros );
|
|
btAssert(m_solveFrictionKernel);
|
|
|
|
m_solveContactKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveContactSource, "BatchSolveKernelContact", &pErrNum, solveContactProg,additionalMacros );
|
|
btAssert(m_solveContactKernel);
|
|
|
|
m_contactToConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetupSource, "ContactToConstraintKernel", &pErrNum, solverSetupProg,additionalMacros );
|
|
btAssert(m_contactToConstraintKernel);
|
|
|
|
m_setSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetSortDataKernel", &pErrNum, solverSetup2Prog,additionalMacros );
|
|
btAssert(m_setSortDataKernel);
|
|
|
|
m_reorderContactKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "ReorderContactKernel", &pErrNum, solverSetup2Prog,additionalMacros );
|
|
btAssert(m_reorderContactKernel);
|
|
|
|
|
|
m_copyConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "CopyConstraintKernel", &pErrNum, solverSetup2Prog,additionalMacros );
|
|
btAssert(m_copyConstraintKernel);
|
|
|
|
}
|
|
|
|
{
|
|
cl_program batchingProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelSource, &pErrNum,additionalMacros, BATCHING_PATH);
|
|
btAssert(batchingProg);
|
|
|
|
m_batchingKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelSource, "CreateBatches", &pErrNum, batchingProg,additionalMacros );
|
|
btAssert(m_batchingKernel);
|
|
}
|
|
{
|
|
cl_program batchingNewProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelNewSource, &pErrNum,additionalMacros, BATCHING_NEW_PATH);
|
|
btAssert(batchingNewProg);
|
|
|
|
m_batchingKernelNew = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelNewSource, "CreateBatchesNew", &pErrNum, batchingNewProg,additionalMacros );
|
|
//m_batchingKernelNew = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelNewSource, "CreateBatchesBruteForce", &pErrNum, batchingNewProg,additionalMacros );
|
|
btAssert(m_batchingKernelNew);
|
|
}
|
|
}
|
|
|
|
b3Solver::~b3Solver()
|
|
{
|
|
delete m_sortDataBuffer;
|
|
delete m_contactBuffer2;
|
|
|
|
delete m_sort32;
|
|
delete m_scan;
|
|
delete m_search;
|
|
|
|
|
|
clReleaseKernel(m_batchingKernel);
|
|
clReleaseKernel(m_batchingKernelNew);
|
|
|
|
clReleaseKernel( m_solveContactKernel);
|
|
clReleaseKernel( m_solveFrictionKernel);
|
|
|
|
clReleaseKernel( m_contactToConstraintKernel);
|
|
clReleaseKernel( m_setSortDataKernel);
|
|
clReleaseKernel( m_reorderContactKernel);
|
|
clReleaseKernel( m_copyConstraintKernel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*void b3Solver::reorderConvertToConstraints( const btOpenCLArray<b3RigidBodyCL>* bodyBuf,
|
|
const btOpenCLArray<btInertiaCL>* shapeBuf,
|
|
btOpenCLArray<b3Contact4>* contactsIn, btOpenCLArray<b3GpuConstraint4>* contactCOut, void* additionalData,
|
|
int nContacts, const b3Solver::ConstraintCfg& cfg )
|
|
{
|
|
if( m_contactBuffer )
|
|
{
|
|
m_contactBuffer->resize(nContacts);
|
|
}
|
|
if( m_contactBuffer == 0 )
|
|
{
|
|
BT_PROFILE("new m_contactBuffer;");
|
|
m_contactBuffer = new btOpenCLArray<b3Contact4>(m_context,m_queue,nContacts );
|
|
m_contactBuffer->resize(nContacts);
|
|
}
|
|
|
|
|
|
|
|
|
|
//DeviceUtils::Config dhCfg;
|
|
//Device* deviceHost = DeviceUtils::allocate( TYPE_HOST, dhCfg );
|
|
if( cfg.m_enableParallelSolve )
|
|
{
|
|
|
|
|
|
clFinish(m_queue);
|
|
|
|
// contactsIn -> m_contactBuffer
|
|
{
|
|
BT_PROFILE("sortContacts");
|
|
sortContacts( bodyBuf, contactsIn, additionalData, nContacts, cfg );
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
|
|
{
|
|
BT_PROFILE("m_copyConstraintKernel");
|
|
|
|
|
|
|
|
btInt4 cdata; cdata.x = nContacts;
|
|
btBufferInfoCL bInfo[] = { btBufferInfoCL( m_contactBuffer->getBufferCL() ), btBufferInfoCL( contactsIn->getBufferCL() ) };
|
|
// btLauncherCL launcher( m_queue, data->m_device->getKernel( PATH, "CopyConstraintKernel", "-I ..\\..\\ -Wf,--c++", 0 ) );
|
|
btLauncherCL launcher( m_queue, m_copyConstraintKernel );
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
launcher.setConst( cdata );
|
|
launcher.launch1D( nContacts, 64 );
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
{
|
|
BT_PROFILE("batchContacts");
|
|
b3Solver::batchContacts( contactsIn, nContacts, m_numConstraints, m_offsets, cfg.m_staticIdx );
|
|
|
|
}
|
|
}
|
|
{
|
|
BT_PROFILE("waitForCompletion (batchContacts)");
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
//================
|
|
|
|
{
|
|
BT_PROFILE("convertToConstraints");
|
|
b3Solver::convertToConstraints( bodyBuf, shapeBuf, contactsIn, contactCOut, additionalData, nContacts, cfg );
|
|
}
|
|
|
|
{
|
|
BT_PROFILE("convertToConstraints waitForCompletion");
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
}
|
|
*/
|
|
|
|
static
|
|
inline
|
|
float calcRelVel(const btVector3& l0, const btVector3& l1, const btVector3& a0, const btVector3& a1,
|
|
const btVector3& linVel0, const btVector3& angVel0, const btVector3& linVel1, const btVector3& angVel1)
|
|
{
|
|
return btDot(l0, linVel0) + btDot(a0, angVel0) + btDot(l1, linVel1) + btDot(a1, angVel1);
|
|
}
|
|
|
|
|
|
static
|
|
inline
|
|
void setLinearAndAngular(const btVector3& n, const btVector3& r0, const btVector3& r1,
|
|
btVector3& linear, btVector3& angular0, btVector3& angular1)
|
|
{
|
|
linear = -n;
|
|
angular0 = -btCross(r0, n);
|
|
angular1 = btCross(r1, n);
|
|
}
|
|
|
|
|
|
template<bool JACOBI>
|
|
static
|
|
__inline
|
|
void solveContact(b3GpuConstraint4& cs,
|
|
const btVector3& posA, btVector3& linVelA, btVector3& angVelA, float invMassA, const btMatrix3x3& invInertiaA,
|
|
const btVector3& posB, btVector3& linVelB, btVector3& angVelB, float invMassB, const btMatrix3x3& invInertiaB,
|
|
float maxRambdaDt[4], float minRambdaDt[4])
|
|
{
|
|
|
|
btVector3 dLinVelA; dLinVelA.setZero();
|
|
btVector3 dAngVelA; dAngVelA.setZero();
|
|
btVector3 dLinVelB; dLinVelB.setZero();
|
|
btVector3 dAngVelB; dAngVelB.setZero();
|
|
|
|
for(int ic=0; ic<4; ic++)
|
|
{
|
|
// dont necessary because this makes change to 0
|
|
if( cs.m_jacCoeffInv[ic] == 0.f ) continue;
|
|
|
|
{
|
|
btVector3 angular0, angular1, linear;
|
|
btVector3 r0 = cs.m_worldPos[ic] - (btVector3&)posA;
|
|
btVector3 r1 = cs.m_worldPos[ic] - (btVector3&)posB;
|
|
setLinearAndAngular( (const btVector3 &)-cs.m_linear, (const btVector3 &)r0, (const btVector3 &)r1, linear, angular0, angular1 );
|
|
|
|
float rambdaDt = calcRelVel((const btVector3 &)cs.m_linear,(const btVector3 &) -cs.m_linear, angular0, angular1,
|
|
linVelA, angVelA, linVelB, angVelB ) + cs.m_b[ic];
|
|
rambdaDt *= cs.m_jacCoeffInv[ic];
|
|
|
|
{
|
|
float prevSum = cs.m_appliedRambdaDt[ic];
|
|
float updated = prevSum;
|
|
updated += rambdaDt;
|
|
updated = btMax( updated, minRambdaDt[ic] );
|
|
updated = btMin( updated, maxRambdaDt[ic] );
|
|
rambdaDt = updated - prevSum;
|
|
cs.m_appliedRambdaDt[ic] = updated;
|
|
}
|
|
|
|
btVector3 linImp0 = invMassA*linear*rambdaDt;
|
|
btVector3 linImp1 = invMassB*(-linear)*rambdaDt;
|
|
btVector3 angImp0 = (invInertiaA* angular0)*rambdaDt;
|
|
btVector3 angImp1 = (invInertiaB* angular1)*rambdaDt;
|
|
#ifdef _WIN32
|
|
btAssert(_finite(linImp0.getX()));
|
|
btAssert(_finite(linImp1.getX()));
|
|
#endif
|
|
if( JACOBI )
|
|
{
|
|
dLinVelA += linImp0;
|
|
dAngVelA += angImp0;
|
|
dLinVelB += linImp1;
|
|
dAngVelB += angImp1;
|
|
}
|
|
else
|
|
{
|
|
linVelA += linImp0;
|
|
angVelA += angImp0;
|
|
linVelB += linImp1;
|
|
angVelB += angImp1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( JACOBI )
|
|
{
|
|
linVelA += dLinVelA;
|
|
angVelA += dAngVelA;
|
|
linVelB += dLinVelB;
|
|
angVelB += dAngVelB;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
__inline
|
|
void solveFriction(b3GpuConstraint4& cs,
|
|
const btVector3& posA, btVector3& linVelA, btVector3& angVelA, float invMassA, const btMatrix3x3& invInertiaA,
|
|
const btVector3& posB, btVector3& linVelB, btVector3& angVelB, float invMassB, const btMatrix3x3& invInertiaB,
|
|
float maxRambdaDt[4], float minRambdaDt[4])
|
|
{
|
|
|
|
if( cs.m_fJacCoeffInv[0] == 0 && cs.m_fJacCoeffInv[0] == 0 ) return;
|
|
const btVector3& center = (const btVector3&)cs.m_center;
|
|
|
|
btVector3 n = -(const btVector3&)cs.m_linear;
|
|
|
|
btVector3 tangent[2];
|
|
#if 1
|
|
btPlaneSpace1 (n, tangent[0],tangent[1]);
|
|
#else
|
|
btVector3 r = cs.m_worldPos[0]-center;
|
|
tangent[0] = cross3( n, r );
|
|
tangent[1] = cross3( tangent[0], n );
|
|
tangent[0] = normalize3( tangent[0] );
|
|
tangent[1] = normalize3( tangent[1] );
|
|
#endif
|
|
|
|
btVector3 angular0, angular1, linear;
|
|
btVector3 r0 = center - posA;
|
|
btVector3 r1 = center - posB;
|
|
for(int i=0; i<2; i++)
|
|
{
|
|
setLinearAndAngular( tangent[i], r0, r1, linear, angular0, angular1 );
|
|
float rambdaDt = calcRelVel(linear, -linear, angular0, angular1,
|
|
linVelA, angVelA, linVelB, angVelB );
|
|
rambdaDt *= cs.m_fJacCoeffInv[i];
|
|
|
|
{
|
|
float prevSum = cs.m_fAppliedRambdaDt[i];
|
|
float updated = prevSum;
|
|
updated += rambdaDt;
|
|
updated = btMax( updated, minRambdaDt[i] );
|
|
updated = btMin( updated, maxRambdaDt[i] );
|
|
rambdaDt = updated - prevSum;
|
|
cs.m_fAppliedRambdaDt[i] = updated;
|
|
}
|
|
|
|
btVector3 linImp0 = invMassA*linear*rambdaDt;
|
|
btVector3 linImp1 = invMassB*(-linear)*rambdaDt;
|
|
btVector3 angImp0 = (invInertiaA* angular0)*rambdaDt;
|
|
btVector3 angImp1 = (invInertiaB* angular1)*rambdaDt;
|
|
#ifdef _WIN32
|
|
btAssert(_finite(linImp0.getX()));
|
|
btAssert(_finite(linImp1.getX()));
|
|
#endif
|
|
linVelA += linImp0;
|
|
angVelA += angImp0;
|
|
linVelB += linImp1;
|
|
angVelB += angImp1;
|
|
}
|
|
|
|
{ // angular damping for point constraint
|
|
btVector3 ab = ( posB - posA ).normalized();
|
|
btVector3 ac = ( center - posA ).normalized();
|
|
if( btDot( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f))
|
|
{
|
|
float angNA = btDot( n, angVelA );
|
|
float angNB = btDot( n, angVelB );
|
|
|
|
angVelA -= (angNA*0.1f)*n;
|
|
angVelB -= (angNB*0.1f)*n;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
struct SolveTask// : public ThreadPool::Task
|
|
{
|
|
SolveTask(btAlignedObjectArray<b3RigidBodyCL>& bodies, btAlignedObjectArray<btInertiaCL>& shapes, btAlignedObjectArray<b3GpuConstraint4>& constraints,
|
|
int start, int nConstraints)
|
|
: m_bodies( bodies ), m_shapes( shapes ), m_constraints( constraints ), m_start( start ), m_nConstraints( nConstraints ),
|
|
m_solveFriction( true ){}
|
|
|
|
unsigned short int getType(){ return 0; }
|
|
|
|
void run(int tIdx)
|
|
{
|
|
|
|
|
|
for(int ic=0; ic<m_nConstraints; ic++)
|
|
{
|
|
int i = m_start + ic;
|
|
|
|
float frictionCoeff = m_constraints[i].getFrictionCoeff();
|
|
int aIdx = (int)m_constraints[i].m_bodyA;
|
|
int bIdx = (int)m_constraints[i].m_bodyB;
|
|
b3RigidBodyCL& bodyA = m_bodies[aIdx];
|
|
b3RigidBodyCL& bodyB = m_bodies[bIdx];
|
|
|
|
if( !m_solveFriction )
|
|
{
|
|
float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};
|
|
float minRambdaDt[4] = {0.f,0.f,0.f,0.f};
|
|
|
|
solveContact<false>( m_constraints[i], (btVector3&)bodyA.m_pos, (btVector3&)bodyA.m_linVel, (btVector3&)bodyA.m_angVel, bodyA.m_invMass, (const btMatrix3x3 &)m_shapes[aIdx].m_invInertiaWorld,
|
|
(btVector3&)bodyB.m_pos, (btVector3&)bodyB.m_linVel, (btVector3&)bodyB.m_angVel, bodyB.m_invMass, (const btMatrix3x3 &)m_shapes[bIdx].m_invInertiaWorld,
|
|
maxRambdaDt, minRambdaDt );
|
|
|
|
}
|
|
else
|
|
{
|
|
float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};
|
|
float minRambdaDt[4] = {0.f,0.f,0.f,0.f};
|
|
|
|
float sum = 0;
|
|
for(int j=0; j<4; j++)
|
|
{
|
|
sum +=m_constraints[i].m_appliedRambdaDt[j];
|
|
}
|
|
frictionCoeff = 0.7f;
|
|
for(int j=0; j<4; j++)
|
|
{
|
|
maxRambdaDt[j] = frictionCoeff*sum;
|
|
minRambdaDt[j] = -maxRambdaDt[j];
|
|
}
|
|
|
|
solveFriction( m_constraints[i], (btVector3&)bodyA.m_pos, (btVector3&)bodyA.m_linVel, (btVector3&)bodyA.m_angVel, bodyA.m_invMass,(const btMatrix3x3 &) m_shapes[aIdx].m_invInertiaWorld,
|
|
(btVector3&)bodyB.m_pos, (btVector3&)bodyB.m_linVel, (btVector3&)bodyB.m_angVel, bodyB.m_invMass,(const btMatrix3x3 &) m_shapes[bIdx].m_invInertiaWorld,
|
|
maxRambdaDt, minRambdaDt );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
btAlignedObjectArray<b3RigidBodyCL>& m_bodies;
|
|
btAlignedObjectArray<btInertiaCL>& m_shapes;
|
|
btAlignedObjectArray<b3GpuConstraint4>& m_constraints;
|
|
int m_start;
|
|
int m_nConstraints;
|
|
bool m_solveFriction;
|
|
};
|
|
|
|
|
|
void b3Solver::solveContactConstraintHost( btOpenCLArray<b3RigidBodyCL>* bodyBuf, btOpenCLArray<btInertiaCL>* shapeBuf,
|
|
btOpenCLArray<b3GpuConstraint4>* constraint, void* additionalData, int n ,int maxNumBatches)
|
|
{
|
|
|
|
btAlignedObjectArray<b3RigidBodyCL> bodyNative;
|
|
bodyBuf->copyToHost(bodyNative);
|
|
btAlignedObjectArray<btInertiaCL> shapeNative;
|
|
shapeBuf->copyToHost(shapeNative);
|
|
btAlignedObjectArray<b3GpuConstraint4> constraintNative;
|
|
constraint->copyToHost(constraintNative);
|
|
|
|
for(int iter=0; iter<m_nIterations; iter++)
|
|
{
|
|
SolveTask task( bodyNative, shapeNative, constraintNative, 0, n );
|
|
task.m_solveFriction = false;
|
|
task.run(0);
|
|
}
|
|
|
|
for(int iter=0; iter<m_nIterations; iter++)
|
|
{
|
|
SolveTask task( bodyNative, shapeNative, constraintNative, 0, n );
|
|
task.m_solveFriction = true;
|
|
task.run(0);
|
|
}
|
|
|
|
bodyBuf->copyFromHost(bodyNative);
|
|
shapeBuf->copyFromHost(shapeNative);
|
|
constraint->copyFromHost(constraintNative);
|
|
|
|
|
|
}
|
|
|
|
void b3Solver::solveContactConstraint( const btOpenCLArray<b3RigidBodyCL>* bodyBuf, const btOpenCLArray<btInertiaCL>* shapeBuf,
|
|
btOpenCLArray<b3GpuConstraint4>* constraint, void* additionalData, int n ,int maxNumBatches)
|
|
{
|
|
|
|
|
|
btInt4 cdata = btMakeInt4( n, 0, 0, 0 );
|
|
{
|
|
|
|
const int nn = N_SPLIT*N_SPLIT;
|
|
|
|
cdata.x = 0;
|
|
cdata.y = maxNumBatches;//250;
|
|
|
|
|
|
int numWorkItems = 64*nn/N_BATCHES;
|
|
#ifdef DEBUG_ME
|
|
SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems];
|
|
adl::btOpenCLArray<SolverDebugInfo> gpuDebugInfo(data->m_device,numWorkItems);
|
|
#endif
|
|
|
|
|
|
|
|
{
|
|
|
|
BT_PROFILE("m_batchSolveKernel iterations");
|
|
for(int iter=0; iter<m_nIterations; iter++)
|
|
{
|
|
for(int ib=0; ib<N_BATCHES; ib++)
|
|
{
|
|
#ifdef DEBUG_ME
|
|
memset(debugInfo,0,sizeof(SolverDebugInfo)*numWorkItems);
|
|
gpuDebugInfo.write(debugInfo,numWorkItems);
|
|
#endif
|
|
|
|
|
|
cdata.z = ib;
|
|
cdata.w = N_SPLIT;
|
|
|
|
btLauncherCL launcher( m_queue, m_solveContactKernel );
|
|
#if 1
|
|
|
|
btBufferInfoCL bInfo[] = {
|
|
|
|
btBufferInfoCL( bodyBuf->getBufferCL() ),
|
|
btBufferInfoCL( shapeBuf->getBufferCL() ),
|
|
btBufferInfoCL( constraint->getBufferCL() ),
|
|
btBufferInfoCL( m_numConstraints->getBufferCL() ),
|
|
btBufferInfoCL( m_offsets->getBufferCL() )
|
|
#ifdef DEBUG_ME
|
|
, btBufferInfoCL(&gpuDebugInfo)
|
|
#endif
|
|
};
|
|
|
|
|
|
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
//launcher.setConst( cdata.x );
|
|
launcher.setConst( cdata.y );
|
|
launcher.setConst( cdata.z );
|
|
launcher.setConst( cdata.w );
|
|
launcher.launch1D( numWorkItems, 64 );
|
|
|
|
|
|
#else
|
|
const char* fileName = "m_batchSolveKernel.bin";
|
|
FILE* f = fopen(fileName,"rb");
|
|
if (f)
|
|
{
|
|
int sizeInBytes=0;
|
|
if (fseek(f, 0, SEEK_END) || (sizeInBytes = ftell(f)) == EOF || fseek(f, 0, SEEK_SET))
|
|
{
|
|
printf("error, cannot get file size\n");
|
|
exit(0);
|
|
}
|
|
|
|
unsigned char* buf = (unsigned char*) malloc(sizeInBytes);
|
|
fread(buf,sizeInBytes,1,f);
|
|
int serializedBytes = launcher.deserializeArgs(buf, sizeInBytes,m_context);
|
|
int num = *(int*)&buf[serializedBytes];
|
|
|
|
launcher.launch1D( num);
|
|
|
|
//this clFinish is for testing on errors
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_ME
|
|
clFinish(m_queue);
|
|
gpuDebugInfo.read(debugInfo,numWorkItems);
|
|
clFinish(m_queue);
|
|
for (int i=0;i<numWorkItems;i++)
|
|
{
|
|
if (debugInfo[i].m_valInt2>0)
|
|
{
|
|
printf("debugInfo[i].m_valInt2 = %d\n",i,debugInfo[i].m_valInt2);
|
|
}
|
|
|
|
if (debugInfo[i].m_valInt3>0)
|
|
{
|
|
printf("debugInfo[i].m_valInt3 = %d\n",i,debugInfo[i].m_valInt3);
|
|
}
|
|
}
|
|
#endif //DEBUG_ME
|
|
|
|
|
|
}
|
|
}
|
|
|
|
clFinish(m_queue);
|
|
|
|
|
|
}
|
|
|
|
cdata.x = 1;
|
|
bool applyFriction=true;
|
|
if (applyFriction)
|
|
{
|
|
BT_PROFILE("m_batchSolveKernel iterations2");
|
|
for(int iter=0; iter<m_nIterations; iter++)
|
|
{
|
|
for(int ib=0; ib<N_BATCHES; ib++)
|
|
{
|
|
cdata.z = ib;
|
|
cdata.w = N_SPLIT;
|
|
|
|
btBufferInfoCL bInfo[] = {
|
|
btBufferInfoCL( bodyBuf->getBufferCL() ),
|
|
btBufferInfoCL( shapeBuf->getBufferCL() ),
|
|
btBufferInfoCL( constraint->getBufferCL() ),
|
|
btBufferInfoCL( m_numConstraints->getBufferCL() ),
|
|
btBufferInfoCL( m_offsets->getBufferCL() )
|
|
#ifdef DEBUG_ME
|
|
,btBufferInfoCL(&gpuDebugInfo)
|
|
#endif //DEBUG_ME
|
|
};
|
|
btLauncherCL launcher( m_queue, m_solveFrictionKernel );
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
//launcher.setConst( cdata.x );
|
|
launcher.setConst( cdata.y );
|
|
launcher.setConst( cdata.z );
|
|
launcher.setConst( cdata.w );
|
|
|
|
launcher.launch1D( 64*nn/N_BATCHES, 64 );
|
|
}
|
|
}
|
|
clFinish(m_queue);
|
|
|
|
}
|
|
#ifdef DEBUG_ME
|
|
delete[] debugInfo;
|
|
#endif //DEBUG_ME
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void b3Solver::convertToConstraints( const btOpenCLArray<b3RigidBodyCL>* bodyBuf,
|
|
const btOpenCLArray<btInertiaCL>* shapeBuf,
|
|
btOpenCLArray<b3Contact4>* contactsIn, btOpenCLArray<b3GpuConstraint4>* contactCOut, void* additionalData,
|
|
int nContacts, const ConstraintCfg& cfg )
|
|
{
|
|
btOpenCLArray<b3GpuConstraint4>* constraintNative =0;
|
|
|
|
struct CB
|
|
{
|
|
int m_nContacts;
|
|
float m_dt;
|
|
float m_positionDrift;
|
|
float m_positionConstraintCoeff;
|
|
};
|
|
|
|
{
|
|
BT_PROFILE("m_contactToConstraintKernel");
|
|
CB cdata;
|
|
cdata.m_nContacts = nContacts;
|
|
cdata.m_dt = cfg.m_dt;
|
|
cdata.m_positionDrift = cfg.m_positionDrift;
|
|
cdata.m_positionConstraintCoeff = cfg.m_positionConstraintCoeff;
|
|
|
|
|
|
btBufferInfoCL bInfo[] = { btBufferInfoCL( contactsIn->getBufferCL() ), btBufferInfoCL( bodyBuf->getBufferCL() ), btBufferInfoCL( shapeBuf->getBufferCL()),
|
|
btBufferInfoCL( contactCOut->getBufferCL() )};
|
|
btLauncherCL launcher( m_queue, m_contactToConstraintKernel );
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
//launcher.setConst( cdata );
|
|
|
|
launcher.setConst(cdata.m_nContacts);
|
|
launcher.setConst(cdata.m_dt);
|
|
launcher.setConst(cdata.m_positionDrift);
|
|
launcher.setConst(cdata.m_positionConstraintCoeff);
|
|
|
|
launcher.launch1D( nContacts, 64 );
|
|
clFinish(m_queue);
|
|
|
|
}
|
|
|
|
contactCOut->resize(nContacts);
|
|
}
|
|
|
|
/*
|
|
void b3Solver::sortContacts( const btOpenCLArray<b3RigidBodyCL>* bodyBuf,
|
|
btOpenCLArray<b3Contact4>* contactsIn, void* additionalData,
|
|
int nContacts, const b3Solver::ConstraintCfg& cfg )
|
|
{
|
|
|
|
|
|
|
|
const int sortAlignment = 512; // todo. get this out of sort
|
|
if( cfg.m_enableParallelSolve )
|
|
{
|
|
|
|
|
|
int sortSize = NEXTMULTIPLEOF( nContacts, sortAlignment );
|
|
|
|
btOpenCLArray<unsigned int>* countsNative = m_numConstraints;//BufferUtils::map<TYPE_CL, false>( data->m_device, &countsHost );
|
|
btOpenCLArray<unsigned int>* offsetsNative = m_offsets;//BufferUtils::map<TYPE_CL, false>( data->m_device, &offsetsHost );
|
|
|
|
{ // 2. set cell idx
|
|
struct CB
|
|
{
|
|
int m_nContacts;
|
|
int m_staticIdx;
|
|
float m_scale;
|
|
int m_nSplit;
|
|
};
|
|
|
|
btAssert( sortSize%64 == 0 );
|
|
CB cdata;
|
|
cdata.m_nContacts = nContacts;
|
|
cdata.m_staticIdx = cfg.m_staticIdx;
|
|
cdata.m_scale = 1.f/(N_OBJ_PER_SPLIT*cfg.m_averageExtent);
|
|
cdata.m_nSplit = N_SPLIT;
|
|
|
|
|
|
btBufferInfoCL bInfo[] = { btBufferInfoCL( contactsIn->getBufferCL() ), btBufferInfoCL( bodyBuf->getBufferCL() ), btBufferInfoCL( m_sortDataBuffer->getBufferCL() ) };
|
|
btLauncherCL launcher( m_queue, m_setSortDataKernel );
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
launcher.setConst( cdata );
|
|
launcher.launch1D( sortSize, 64 );
|
|
}
|
|
|
|
{ // 3. sort by cell idx
|
|
int n = N_SPLIT*N_SPLIT;
|
|
int sortBit = 32;
|
|
//if( n <= 0xffff ) sortBit = 16;
|
|
//if( n <= 0xff ) sortBit = 8;
|
|
m_sort32->execute(*m_sortDataBuffer,sortSize);
|
|
}
|
|
{ // 4. find entries
|
|
m_search->execute( *m_sortDataBuffer, nContacts, *countsNative, N_SPLIT*N_SPLIT, btBoundSearchCL::COUNT);
|
|
|
|
m_scan->execute( *countsNative, *offsetsNative, N_SPLIT*N_SPLIT );
|
|
}
|
|
|
|
{ // 5. sort constraints by cellIdx
|
|
// todo. preallocate this
|
|
// btAssert( contactsIn->getType() == TYPE_HOST );
|
|
// btOpenCLArray<b3Contact4>* out = BufferUtils::map<TYPE_CL, false>( data->m_device, contactsIn ); // copying contacts to this buffer
|
|
|
|
{
|
|
|
|
|
|
btInt4 cdata; cdata.x = nContacts;
|
|
btBufferInfoCL bInfo[] = { btBufferInfoCL( contactsIn->getBufferCL() ), btBufferInfoCL( m_contactBuffer->getBufferCL() ), btBufferInfoCL( m_sortDataBuffer->getBufferCL() ) };
|
|
btLauncherCL launcher( m_queue, m_reorderContactKernel );
|
|
launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(btBufferInfoCL) );
|
|
launcher.setConst( cdata );
|
|
launcher.launch1D( nContacts, 64 );
|
|
}
|
|
// BufferUtils::unmap<true>( out, contactsIn, nContacts );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
void b3Solver::batchContacts( btOpenCLArray<b3Contact4>* contacts, int nContacts, btOpenCLArray<unsigned int>* nNative, btOpenCLArray<unsigned int>* offsetsNative, int staticIdx )
|
|
{
|
|
|
|
int numWorkItems = 64*N_SPLIT*N_SPLIT;
|
|
{
|
|
BT_PROFILE("batch generation");
|
|
|
|
btInt4 cdata;
|
|
cdata.x = nContacts;
|
|
cdata.y = 0;
|
|
cdata.z = staticIdx;
|
|
|
|
|
|
#ifdef BATCH_DEBUG
|
|
SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems];
|
|
adl::btOpenCLArray<SolverDebugInfo> gpuDebugInfo(data->m_device,numWorkItems);
|
|
memset(debugInfo,0,sizeof(SolverDebugInfo)*numWorkItems);
|
|
gpuDebugInfo.write(debugInfo,numWorkItems);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
btBufferInfoCL bInfo[] = {
|
|
btBufferInfoCL( contacts->getBufferCL() ),
|
|
btBufferInfoCL( m_contactBuffer2->getBufferCL()),
|
|
btBufferInfoCL( nNative->getBufferCL() ),
|
|
btBufferInfoCL( offsetsNative->getBufferCL() ),
|
|
#ifdef BATCH_DEBUG
|
|
, btBufferInfoCL(&gpuDebugInfo)
|
|
#endif
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
BT_PROFILE("batchingKernel");
|
|
//btLauncherCL launcher( m_queue, m_batchingKernel);
|
|
cl_kernel k = useNewBatchingKernel ? m_batchingKernelNew : m_batchingKernel;
|
|
|
|
btLauncherCL launcher( m_queue, k);
|
|
if (!useNewBatchingKernel )
|
|
{
|
|
launcher.setBuffer( contacts->getBufferCL() );
|
|
}
|
|
launcher.setBuffer( m_contactBuffer2->getBufferCL() );
|
|
launcher.setBuffer( nNative->getBufferCL());
|
|
launcher.setBuffer( offsetsNative->getBufferCL());
|
|
|
|
//launcher.setConst( cdata );
|
|
launcher.setConst(staticIdx);
|
|
|
|
launcher.launch1D( numWorkItems, 64 );
|
|
clFinish(m_queue);
|
|
}
|
|
|
|
#ifdef BATCH_DEBUG
|
|
aaaa
|
|
b3Contact4* hostContacts = new b3Contact4[nContacts];
|
|
m_contactBuffer->read(hostContacts,nContacts);
|
|
clFinish(m_queue);
|
|
|
|
gpuDebugInfo.read(debugInfo,numWorkItems);
|
|
clFinish(m_queue);
|
|
|
|
for (int i=0;i<numWorkItems;i++)
|
|
{
|
|
if (debugInfo[i].m_valInt1>0)
|
|
{
|
|
printf("catch\n");
|
|
}
|
|
if (debugInfo[i].m_valInt2>0)
|
|
{
|
|
printf("catch22\n");
|
|
}
|
|
|
|
if (debugInfo[i].m_valInt3>0)
|
|
{
|
|
printf("catch666\n");
|
|
}
|
|
|
|
if (debugInfo[i].m_valInt4>0)
|
|
{
|
|
printf("catch777\n");
|
|
}
|
|
}
|
|
delete[] debugInfo;
|
|
#endif //BATCH_DEBUG
|
|
|
|
}
|
|
|
|
// copy buffer to buffer
|
|
//btAssert(m_contactBuffer->size()==nContacts);
|
|
//contacts->copyFromOpenCLArray( *m_contactBuffer);
|
|
//clFinish(m_queue);//needed?
|
|
|
|
|
|
|
|
}
|
|
|