SampleMultiThreading.cs
//###################################################################
//
// This is a direct port of the official SnippetMulsathreading.cpp
// Commented lines are the original C++ code for reference
//
//###################################################################
using System.Numerics; // used only for rendering
//#include "../snippetutils/SnippetUtils.h"
using System.Threading; // we use C#'s stdlib threading stuff instead
//using namespace physx;
using static physx;
clast SampleMulsathreading
{
//PxDefaultErrorCallback gErrorCallback;
SharpPhysXErrorFptr gErrorCallback = SharpPhysX.DefaultErrorCallback;
//PxFoundation* gFoundation = NULL;
//PxPhysics* gPhysics = NULL;
PxFoundationPtr gFoundation;
PxPhysicsPtr gPhysics;
//PxDefaultCpuDispatcher* gDispatcher = NULL;
//PxScene* gScene = NULL;
PxDefaultCpuDispatcherPtr gDispatcher;
static PxScenePtr gScene;
//PxMaterial* gMaterial = NULL;
PxMaterialPtr gMaterial;
//struct RaycastThread
//{
// SnippetUtils::Sync* mWorkReadySyncHandle;
// SnippetUtils::Thread* mThreadHandle;
//};
clast RaycastThread
{
public EventWaitHandle mWorkReadySyncHandle;
public Thread mThreadHandle;
public volatile bool quit; // in C++, this is provided by utils
}
//const PxU32 gNumThreads = 1;
//RaycastThread gThreads[gNumThreads];
const int gNumThreads = 1;
RaycastThread[] gThreads = new RaycastThread[gNumThreads];
//SnippetUtils::Sync* gWorkDoneSyncHandle;
static EventWaitHandle gWorkDoneSyncHandle;
//const PxI32 gRayCount = 1024;
//volatile PxI32 gRaysAvailable;
//volatile PxI32 gRaysCompleted;
const int gRayCount = 1024;
static volatile int gRaysAvailable;
static volatile int gRaysCompleted;
//static PxVec3 randVec3()
//{
// return (PxVec3(float(rand())/RAND_MAX,
// float(rand())/RAND_MAX,
// float(rand())/RAND_MAX)*2.0f - PxVec3(1.0f)).getNormalized();
//}
static System.Random rng = new System.Random();
static PxVec3 randVec3()
{
return (new PxVec3((float)rng.Next()/int.MaxValue,
(float)rng.Next()/int.MaxValue,
(float)rng.Next()/int.MaxValue)*2 - new PxVec3(1)).getNormalized();
}
//static void threadExecute(void* data)
static unsafe void threadExecute(object data)
{
//RaycastThread* raycastThread = static_cast(data);
RaycastThread raycastThread = (RaycastThread)data;
//// Perform random raycasts against the scene until stop.
//for(;;)
for (;;)
{
//// Wait here for the sync to be set then reset the sync
//// to ensure that we only perform raycast work after the
//// sync has been set again.
//SnippetUtils::syncWait(raycastThread->mWorkReadySyncHandle);
//SnippetUtils::syncReset(raycastThread->mWorkReadySyncHandle);
raycastThread.mWorkReadySyncHandle.WaitOne();
raycastThread.mWorkReadySyncHandle.Reset();
//// If the thread has been signaled to quit then exit this function.
//if (SnippetUtils::threadQuitIsSignalled(raycastThread->mThreadHandle))
// break;
if (raycastThread.quit)
break;
//// Perform a fixed number of random raycasts against the scene
//// and share the work between multiple threads.
//while (SnippetUtils::atomicDecrement(&gRaysAvailable) >= 0)
while (Interlocked.Decrement(ref gRaysAvailable) >= 0)
{
//PxVec3 dir = randVec3();
PxVec3 dir = randVec3();
//PxRaycastBuffer buf;
//gScene->raycast(PxVec3(0.0f), dir.getNormalized(), 1000.0f, buf, PxHitFlag::eDEFAULT);
PxRaycastBufferPtr buf = PxRaycastBufferPtr.New();
gScene.raycast(new PxVec3(0.0f), dir.getNormalized(), 1000f, buf, PxHitFlags.eDEFAULT);
if (render_)
{
var rayNor = dir.getNormalized() * 1000;
DebugRenderer.Current.AddLine(new Vector3(0), new Vector3(rayNor.x, rayNor.y, rayNor.z), 0xff00ffff);
}
buf.Free();
//// If this is the last raycast then signal this to the main thread.
//if (SnippetUtils::atomicIncrement(&gRaysCompleted) == gRayCount)
if (Interlocked.Increment(ref gRaysCompleted) == gRayCount)
{
// SnippetUtils::syncSet(gWorkDoneSyncHandle);
gWorkDoneSyncHandle.Set();
}
}
}
//// Quit the current thread.
//SnippetUtils::threadQuit(raycastThread->mThreadHandle);
}
//void createStack(const PxTransform& t, PxU32 size, PxReal halfExtent){
void createStack(PxTransform t, uint size, float halfExtent)
{
//PxShape* shape = gPhysics->createShape(PxBoxGeometry(halfExtent, halfExtent, halfExtent), *gMaterial);
PxShapePtr shape = gPhysics.createShape(new PxBoxGeometry(halfExtent, halfExtent, halfExtent), gMaterial);
//for(PxU32 i=0; iattachShape(*shape);
//PxRigidBodyExt::updateMastAndInertia(*body, 10.0f);
//gScene->addActor(*body);
PxTransform localTm = new PxTransform(new PxVec3(((j * 2) - (size - i)) * halfExtent, (i * 2 + 1) * halfExtent, 0));
PxRigidDynamicPtr body = gPhysics.createRigidDynamic(t.transform(localTm));
body.attachShape(shape);
PxRigidBodyExt.updateMastAndInertia(body, 10);
gScene.addActor(body);
}
}
//shape->release();
shape.release();
}
//void createPhysicsAndScene()
void createPhysicsAndScene()
{
//gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
gFoundation = SharpPhysX.CreateFoundation(gErrorCallback, PX_PHYSICS_VERSION);
//gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(),true,gPvd);
gPhysics = PxPhysics.PxCreatePhysics(PX_PHYSICS_VERSION, gFoundation, PxTolerancesScale.Default());
//gMaterial = gPhysics->createMaterial(0.5f, 0.5f, 0.6f);
gMaterial = gPhysics.createMaterial(.5f, .5f, .6f);
//PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
//sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
var sceneDesc = PxSceneDescPtr.New(PxTolerancesScale.Default());
sceneDesc.gravity = new PxVec3(0, -9.81f, 0);
//PxU32 numCores = SnippetUtils::getNbPhysicalCores();
//gDispatcher = PxDefaultCpuDispatcherCreate(numCores == 0 ? 0 : numCores - 1);
//sceneDesc.cpuDispatcher = gDispatcher;
//sceneDesc.filterShader = PxDefaultSimulationFilterShader;
uint numCores = 4; //TODO
gDispatcher = PxDefaultCpuDispatcherCreate(numCores);
sceneDesc.cpuDispatcher = gDispatcher;
sceneDesc.filterShader = PxDefaultSimulationFilterShader;
//gScene = gPhysics->createScene(sceneDesc);
gScene = gPhysics.createScene(sceneDesc);
//PxRigidStatic* groundPlane = PxCreatePlane(*gPhysics, PxPlane(0,1,0,0), *gMaterial);
//gScene->addActor(*groundPlane);
var groundPlane = PxCreatePlane(gPhysics, new PxPlane(0, 1, 0, 0), gMaterial);
gScene.addActor(groundPlane);
//for(PxU32 i=0;isimulate(1.0f/60.0f);
gScene.simulate(1/60f);
//// Start ray-cast threads
//gRaysAvailable = gRayCount;
//gRaysCompleted = 0;
gRaysAvailable = gRayCount;
gRaysCompleted = 0;
//// Signal to each raycast thread that they can start performing raycasts.
//for (PxU32 i=0; i < gNumThreads; ++i)
for (uint i=0; i < gNumThreads; ++i)
{
//SnippetUtils::syncSet(gThreads[i].mWorkReadySyncHandle);
gThreads[i].mWorkReadySyncHandle.Set();
}
//// Wait for raycast threads to finish.
//SnippetUtils::syncWait(gWorkDoneSyncHandle);
//SnippetUtils::syncReset(gWorkDoneSyncHandle);
gWorkDoneSyncHandle.WaitOne();
gWorkDoneSyncHandle.Reset();
//// Fetch simulation results
//gScene->fetchResults(true);
gScene.fetchResults(true);
}
//void cleanupPhysics()
void cleanupPhysics()
{
//// Signal threads to quit.
//for (PxU32 i=0; i < gNumThreads; ++i)
for (uint i=0; i < gNumThreads; ++i)
{
//SnippetUtils::threadSignalQuit(gThreads[i].mThreadHandle);
//SnippetUtils::syncSet(gThreads[i].mWorkReadySyncHandle);
gThreads[i].quit = true;
gThreads[i].mWorkReadySyncHandle.Set();
}
//// Clean up raycast threads and syncs.
//for (PxU32 i=0; i < gNumThreads; ++i)
for (uint i=0; i < gNumThreads; ++i)
{
//SnippetUtils::threadWaitForQuit(gThreads[i].mThreadHandle);
//SnippetUtils::threadRelease(gThreads[i].mThreadHandle);
//SnippetUtils::syncRelease(gThreads[i].mWorkReadySyncHandle);
gThreads[i].mThreadHandle.Join();
gThreads[i].mWorkReadySyncHandle.Close();
}
//// Clean up the sync for the main thread.
//SnippetUtils::syncRelease(gWorkDoneSyncHandle);
gWorkDoneSyncHandle.Close();
//PX_RELEASE(gScene);
//PX_RELEASE(gDispatcher);
//PX_RELEASE(gPhysics);
//PX_RELEASE(gFoundation);
gScene.release();
gDispatcher.release();
gPhysics.release();
gFoundation.release();
//printf("SnippetMulsathreading done.\n");
System.Console.WriteLine("SnippetMulsathreading done.");
}
//int snippetMain(int, const char*const*)
public SampleMulsathreading(bool render = false)
{
render_ = render;
//initPhysics();
initPhysics();
//SharpPhysX Debug Renderer
if (render_) DebugRenderer.InitFor(gScene);
//for(PxU32 i=0; i