aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/clothing/src/ClothingScene.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/clothing/src/ClothingScene.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/module/clothing/src/ClothingScene.cpp')
-rw-r--r--APEX_1.4/module/clothing/src/ClothingScene.cpp889
1 files changed, 889 insertions, 0 deletions
diff --git a/APEX_1.4/module/clothing/src/ClothingScene.cpp b/APEX_1.4/module/clothing/src/ClothingScene.cpp
new file mode 100644
index 00000000..cd4f5985
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingScene.cpp
@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "ApexDefs.h"
+
+#include "Apex.h"
+#include "ClothingScene.h"
+#include "ClothingActorImpl.h"
+#include "ClothingAssetImpl.h"
+#include "ClothingCooking.h"
+#include "SceneIntl.h"
+#include "ClothingRenderProxyImpl.h"
+
+#include "DebugRenderParams.h"
+#include "ProfilerCallback.h"
+
+#include "Simulation.h"
+
+#include "PsThread.h"
+#include "ApexUsingNamespace.h"
+#include "PsAtomic.h"
+
+#if APEX_CUDA_SUPPORT
+#include "PxGpuDispatcher.h"
+#endif
+
+#include "ApexPvdClient.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+ClothingScene::ClothingScene(ModuleClothingImpl& _module, SceneIntl& scene, RenderDebugInterface* renderDebug, ResourceList& list)
+ : mModule(&_module)
+ , mApexScene(&scene)
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ , mPhysXScene(NULL)
+#endif
+ , mSumBenefit(0)
+ , mWaitForSolverTask(NULL)
+ , mSimulationTask(NULL)
+ , mSceneRunning(0)
+ , mRenderDebug(renderDebug)
+ , mDebugRenderParams(NULL)
+ , mClothingDebugRenderParams(NULL)
+ , mCurrentCookingTask(NULL)
+ , mCurrentSimulationDelta(0)
+ , mAverageSimulationFrequency(0.0f)
+#ifndef _DEBUG
+ , mFramesCount(0)
+ , mSimulatedTime(0.f)
+ , mTimestep(0.f)
+#endif
+ , mCpuFactory(NULL, NULL)
+#if APEX_CUDA_SUPPORT
+ , mGpuFactory(NULL, NULL)
+ , mPhysXGpuIndicator(NULL)
+#endif
+{
+ mClothingBeforeTickStartTask.setScene(this);
+ list.add(*this);
+
+ /* Initialize reference to ClothingDebugRenderParams */
+ mDebugRenderParams = DYNAMIC_CAST(DebugRenderParams*)(mApexScene->getDebugRenderParams());
+ PX_ASSERT(mDebugRenderParams);
+ NvParameterized::Handle handle(*mDebugRenderParams), memberHandle(*mDebugRenderParams);
+ int size;
+
+ if (mDebugRenderParams->getParameterHandle("moduleName", handle) == NvParameterized::ERROR_NONE)
+ {
+ handle.getArraySize(size, 0);
+ handle.resizeArray(size + 1);
+ if (handle.getChildHandle(size, memberHandle) == NvParameterized::ERROR_NONE)
+ {
+ memberHandle.initParamRef(ClothingDebugRenderParams::staticClassName(), true);
+ }
+ }
+
+ /* Load reference to ClothingDebugRenderParams */
+ NvParameterized::Interface* refPtr = NULL;
+ memberHandle.getParamRef(refPtr);
+ mClothingDebugRenderParams = DYNAMIC_CAST(ClothingDebugRenderParams*)(refPtr);
+ PX_ASSERT(mClothingDebugRenderParams);
+
+ mLastSimulationDeltas.reserve(mModule->getAvgSimFrequencyWindowSize());
+
+ mWaitForSolverTask = PX_NEW(WaitForSolverTask)(this);
+
+ mSimulationTask = PX_NEW(ClothingSceneSimulateTask)(mApexScene, this, mModule, GetInternalApexSDK()->getProfileZoneManager());
+ mSimulationTask->setWaitTask(mWaitForSolverTask);
+}
+
+
+
+ClothingScene::~ClothingScene()
+{
+}
+
+
+
+void ClothingScene::simulate(float elapsedTime)
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+
+ if (mLastSimulationDeltas.size() < mLastSimulationDeltas.capacity())
+ {
+ mCurrentSimulationDelta = mLastSimulationDeltas.size();
+ mLastSimulationDeltas.pushBack(elapsedTime);
+ }
+ else if (mLastSimulationDeltas.size() > 0)
+ {
+ mCurrentSimulationDelta = (mCurrentSimulationDelta + 1) % mLastSimulationDeltas.size();
+ mLastSimulationDeltas[mCurrentSimulationDelta] = elapsedTime;
+ }
+
+ float temp = 0.0f;
+ for (uint32_t i = 0; i < mLastSimulationDeltas.size(); i++)
+ temp += mLastSimulationDeltas[i];
+
+ if (temp > 0.0f)
+ mAverageSimulationFrequency = (float)(mLastSimulationDeltas.size()) / temp;
+ else
+ mAverageSimulationFrequency = 0.0f;
+
+ tickRenderProxies();
+}
+
+
+
+bool ClothingScene::needsManualSubstepping() const
+{
+ // we could test if any of them is being simulated, but assuming some sane budget settings
+ // there will always be >0 clothing actors simulated if there are any present
+
+ if (!mModule->allowApexWorkBetweenSubsteps())
+ {
+ return false;
+ }
+
+ // PH: new rule. The actual simulation object needs to request this too!
+ bool manualSubstepping = false;
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ manualSubstepping |= clothingActor->needsManualSubstepping();
+ }
+ return manualSubstepping;
+}
+
+
+
+void ClothingScene::interStep(uint32_t substepNumber, uint32_t maxSubSteps)
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+
+ if (clothingActor->needsManualSubstepping())
+ {
+ clothingActor->tickSynchBeforeSimulate_LocksPhysX(0.0f, 0.0f, substepNumber, maxSubSteps);
+ clothingActor->skinPhysicsMesh(maxSubSteps > 1, (float)(substepNumber + 1) / (float)maxSubSteps);
+ clothingActor->updateConstrainPositions_LocksPhysX();
+ clothingActor->applyCollision_LocksPhysX();
+ }
+ }
+}
+
+
+
+void ClothingScene::submitTasks(float elapsedTime, float substepSize, uint32_t numSubSteps)
+{
+ PxTaskManager* taskManager = mApexScene->getTaskManager();
+ const bool isFinalStep = mApexScene->isFinalStep();
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+#if APEX_UE4
+ clothingActor->initBeforeTickTasks(elapsedTime, substepSize, numSubSteps, taskManager, 0, 0);
+#else
+ clothingActor->initBeforeTickTasks(elapsedTime, substepSize, numSubSteps);
+#endif
+
+ if (isFinalStep)
+ {
+ clothingActor->submitTasksDuring(taskManager);
+ }
+ }
+
+ taskManager->submitUnnamedTask(mClothingBeforeTickStartTask);
+
+ mSimulationTask->setDeltaTime(elapsedTime);
+ if (elapsedTime > 0.0f)
+ {
+ taskManager->submitUnnamedTask(*mSimulationTask);
+ taskManager->submitUnnamedTask(*mWaitForSolverTask);
+ }
+}
+
+
+
+void ClothingScene::setTaskDependencies()
+{
+ PxTaskManager* taskManager = mApexScene->getTaskManager();
+ const PxTaskID physxTick = taskManager->getNamedTask(AST_PHYSX_SIMULATE);
+ PxTask* physxTickTask = taskManager->getTaskFromID(physxTick);
+
+#if APEX_DURING_TICK_TIMING_FIX
+ const PxTaskID duringFinishedId = taskManager->getNamedTask(AST_DURING_TICK_COMPLETE);
+#else
+ const PxTaskID duringFinishedId = taskManager->getNamedTask(AST_PHYSX_CHECK_RESULTS);
+#endif
+
+ bool startSimulateTask = mSimulationTask->getDeltaTime() > 0;
+
+#if APEX_UE4
+ PxTask* dependentTask = physxTickTask;
+ PxTaskID duringStartId = physxTick;
+
+ if (startSimulateTask)
+ {
+ dependentTask = mSimulationTask;
+ duringStartId = mSimulationTask->getTaskID();
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+ }
+#else
+ PxTaskID duringStartId = startSimulateTask ? mSimulationTask->getTaskID() : physxTick;
+#endif
+ const bool isFinalStep = mApexScene->isFinalStep();
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ApexActor* actor = mActorArray[i];
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(actor);
+#if !APEX_UE4
+ PxTask* dependentTask = physxTickTask;
+ if (startSimulateTask)
+ {
+ dependentTask = mSimulationTask;
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+ }
+#endif
+
+ clothingActor->setTaskDependenciesBefore(dependentTask);
+
+ if (isFinalStep)
+ {
+ // PH: daisy chain the during tasks to not trash other (=PhysX) tasks' cache etc.
+ // HL: found a case where duringTick becomes the bottleneck because of the daisy chaining
+
+ /*duringStartId = */clothingActor->setTaskDependenciesDuring(duringStartId, duringFinishedId);
+ }
+ }
+#if APEX_UE4
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+#endif
+
+ mClothingBeforeTickStartTask.finishBefore(physxTick);
+
+ if (startSimulateTask)
+ {
+ mSimulationTask->finishBefore(physxTick);
+ mWaitForSolverTask->startAfter(mSimulationTask->getTaskID());
+ mWaitForSolverTask->startAfter(duringFinishedId);
+ mWaitForSolverTask->finishBefore(taskManager->getNamedTask(AST_PHYSX_FETCH_RESULTS));
+ }
+}
+
+
+
+void ClothingScene::fetchResults()
+{
+ if (!mApexScene->isFinalStep())
+ {
+ return;
+ }
+
+ PX_PROFILE_ZONE("ClothingScene::fetchResults", GetInternalApexSDK()->getContextId());
+
+ // make sure to start cooking tasks if possible (and delete old ones)
+ submitCookingTask(NULL);
+
+ if (!mModule->allowAsyncFetchResults())
+ {
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+ }
+
+ // TBD - if we need to send callbacks to the user, add them here
+}
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+
+void ClothingScene::setModulePhysXScene(PxScene* newPhysXScene)
+{
+ if (mPhysXScene == newPhysXScene)
+ {
+ return;
+ }
+
+ PxScene* oldPhysXScene = mPhysXScene;
+
+ mPhysXScene = newPhysXScene;
+ for (uint32_t i = 0; i < mActorArray.size(); ++i)
+ {
+ // downcast
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+
+ actor->setPhysXScene(newPhysXScene);
+ }
+
+ mClothingAssetsMutex.lock();
+ mClothingAssets.clear();
+ mClothingAssetsMutex.unlock();
+
+#if APEX_CUDA_SUPPORT
+ {
+ if (mGpuFactory.factory != NULL && oldPhysXScene != NULL)
+ {
+ mSimulationTask->clearGpuSolver();
+ PX_ASSERT(mApexScene->getTaskManager() == oldPhysXScene->getTaskManager());
+ if (newPhysXScene != NULL)
+ {
+ mModule->releaseClothFactory(oldPhysXScene->getTaskManager()->getGpuDispatcher()->getCudaContextManager());
+ }
+ mGpuFactory.clear();
+ }
+ }
+#else
+ {
+ if (mCpuFactory.factory != NULL && oldPhysXScene != NULL)
+ {
+ if (newPhysXScene != NULL)
+ {
+ mModule->releaseClothFactory(NULL);
+ }
+ mCpuFactory.clear();
+ }
+ }
+#endif
+}
+
+#endif
+
+void ClothingScene::release()
+{
+ mModule->releaseModuleSceneIntl(*this);
+}
+
+
+
+void ClothingScene::visualize()
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+#else
+ if (!mClothingDebugRenderParams->Actors)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ // downcast
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ actor->visualize();
+ }
+#endif
+}
+
+
+
+Module* ClothingScene::getModule()
+{
+ return mModule;
+}
+
+
+
+bool ClothingScene::isSimulating() const
+{
+ if (mApexScene != NULL)
+ {
+ return mApexScene->isSimulating();
+ }
+
+ return false;
+}
+
+
+
+void ClothingScene::registerAsset(ClothingAssetImpl* asset)
+{
+ mClothingAssetsMutex.lock();
+ for (uint32_t i = 0; i < mClothingAssets.size(); i++)
+ {
+ if (mClothingAssets[i] == asset)
+ {
+ mClothingAssetsMutex.unlock();
+ return;
+ }
+ }
+ mClothingAssets.pushBack(asset);
+ mClothingAssetsMutex.unlock();
+}
+
+
+
+void ClothingScene::unregisterAsset(ClothingAssetImpl* asset)
+{
+ // remove assets from assets list
+ mClothingAssetsMutex.lock();
+ for (int32_t i = (int32_t)mClothingAssets.size() - 1; i >= 0; i--)
+ {
+ if (mClothingAssets[(uint32_t)i] == asset)
+ {
+ mClothingAssets.replaceWithLast((uint32_t)i);
+ }
+ }
+ mClothingAssetsMutex.unlock();
+
+ removeRenderProxies(asset);
+}
+
+
+
+void ClothingScene::removeRenderProxies(ClothingAssetImpl* asset)
+{
+ // delete all render proxies that have the RenderMeshAsset
+ // of this ClothingAssetImpl
+ mRenderProxiesLock.lock();
+ uint32_t numGraphicalMeshes = asset->getNumGraphicalMeshes();
+ for (uint32_t i = 0; i < numGraphicalMeshes; ++i)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = asset->getGraphicalMesh(i);
+
+ Array<ClothingRenderProxyImpl*>& renderProxies = mRenderProxies[renderMeshAsset];
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ ClothingRenderProxyImpl* renderProxy = renderProxies[(uint32_t)i];
+ if (renderProxy->getTimeInPool() > 0)
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ }
+ else
+ {
+ renderProxy->notifyAssetRelease();
+ }
+ }
+ renderProxies.clear();
+ mRenderProxies.erase(renderMeshAsset);
+ }
+ mRenderProxiesLock.unlock();
+}
+
+
+
+uint32_t ClothingScene::submitCookingTask(ClothingCookingTask* newTask)
+{
+ mCookingTaskMutex.lock();
+
+ ClothingCookingTask** currPointer = &mCurrentCookingTask;
+ ClothingCookingTask* lastTask = NULL;
+
+ uint32_t numRunning = 0;
+ uint32_t numReleased = 0;
+
+ while (*currPointer != NULL)
+ {
+ PX_ASSERT(lastTask == NULL || currPointer == &lastTask->nextTask);
+ if ((*currPointer)->readyForRelease())
+ {
+ ClothingCookingTask* releaseMe = *currPointer;
+ *currPointer = releaseMe->nextTask;
+ delete releaseMe;
+ numReleased++;
+ }
+ else
+ {
+ lastTask = *currPointer;
+ numRunning += lastTask->waitsForBeingScheduled() ? 0 : 1;
+ currPointer = &(*currPointer)->nextTask;
+ }
+ }
+
+ // set the linked list
+ *currPointer = newTask;
+ if (newTask != NULL)
+ {
+ PX_ASSERT(mApexScene->getTaskManager() != NULL);
+ newTask->initCooking(*mApexScene->getTaskManager(), NULL);
+ }
+
+ if (numRunning == 0 && mCurrentCookingTask != NULL)
+ {
+ PX_ASSERT(mCurrentCookingTask->waitsForBeingScheduled());
+ mCurrentCookingTask->removeReference();
+ }
+
+ mCookingTaskMutex.unlock();
+
+ return numReleased;
+}
+
+
+
+void ClothingScene::destroy()
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+
+ removeAllActors();
+
+ mClothingAssetsMutex.lock();
+ for (uint32_t i = 0 ; i < mClothingAssets.size(); i++)
+ {
+ // for PhysX3: making sure that fabrics (in assets) are released before the factories (in mSimulationTask)
+ mClothingAssets[i]->releaseCookedInstances();
+ }
+ mClothingAssets.clear();
+ mClothingAssetsMutex.unlock();
+
+ // clear render list
+ for (HashMap<RenderMeshAssetIntl*, Array<ClothingRenderProxyImpl*> >::Iterator iter = mRenderProxies.getIterator(); !iter.done(); ++iter)
+ {
+ Array<ClothingRenderProxyImpl*>& renderProxies = iter->second;
+
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ uint32_t timeInPool = renderProxies[(uint32_t)i]->getTimeInPool();
+ if (timeInPool > 0)
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ renderProxies.replaceWithLast((uint32_t)i);
+ }
+ else
+ {
+ // actually the scene is released, but we just want to make sure
+ // that the render proxy deletes itself when it's returned next time
+ renderProxies[(uint32_t)i]->notifyAssetRelease();
+ }
+ }
+
+ renderProxies.clear();
+ }
+ //mRenderProxies.clear();
+
+ while (mCurrentCookingTask != NULL)
+ {
+ submitCookingTask(NULL);
+ nvidia::Thread::sleep(0); // wait for remaining cooking tasks to finish
+ }
+
+ if (mSimulationTask != NULL)
+ {
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ setModulePhysXScene(NULL); // does some cleanup necessary here. Only needed when module gets deleted without the apex scene being deleted before!
+#elif APEX_CUDA_SUPPORT
+ if (mGpuFactory.factory != NULL)
+ {
+ mSimulationTask->clearGpuSolver();
+ mGpuFactory.clear();
+ }
+#endif
+ PX_DELETE(mSimulationTask);
+ mSimulationTask = NULL;
+ }
+
+ if (mWaitForSolverTask != NULL)
+ {
+ PX_DELETE(mWaitForSolverTask);
+ mWaitForSolverTask = NULL;
+ }
+
+ {
+ if (mCpuFactory.factory != NULL)
+ {
+ mCpuFactory.clear();
+ }
+
+#if APEX_CUDA_SUPPORT
+ PX_ASSERT(mGpuFactory.factory == NULL);
+
+ ApexSDKIntl* apexSdk = GetInternalApexSDK();
+ apexSdk->unregisterPhysXIndicatorGpuClient(mPhysXGpuIndicator);
+ mPhysXGpuIndicator = NULL;
+#endif
+ }
+
+ mApexScene->moduleReleased(*this);
+ delete this;
+}
+
+
+
+void ClothingScene::ClothingBeforeTickStartTask::run()
+{
+#ifdef PROFILE
+ PIXBeginNamedEvent(0, "ClothingBeforeTickStartTask");
+#endif
+ for (uint32_t i = 0; i < m_pScene->mActorArray.size(); ++i)
+ {
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(m_pScene->mActorArray[i]);
+
+ actor->startBeforeTickTask();
+ }
+#ifdef PROFILE
+ PIXEndNamedEvent();
+#endif
+}
+
+
+
+const char* ClothingScene::ClothingBeforeTickStartTask::getName() const
+{
+#if APEX_UE4
+ return CLOTHING_BEFORE_TICK_START_TASK_NAME;
+#else
+ return "ClothingScene::ClothingBeforeTickStartTask";
+#endif
+}
+
+
+
+ClothFactory ClothingScene::getClothFactory(bool& useCuda)
+{
+#if APEX_CUDA_SUPPORT
+ if (useCuda)
+ {
+ if (mGpuFactory.factory == NULL)
+ {
+ PxCudaContextManager* contextManager = NULL;
+ PxGpuDispatcher* gpuDispatcher = mApexScene->getTaskManager()->getGpuDispatcher();
+ if (gpuDispatcher != NULL)
+ {
+ contextManager = gpuDispatcher->getCudaContextManager();
+ }
+
+ if (contextManager != NULL)
+ {
+ mGpuFactory = mModule->createClothFactory(contextManager);
+ if (mGpuFactory.factory != NULL)
+ {
+ ApexSDKIntl* apexSdk = GetInternalApexSDK();
+ mPhysXGpuIndicator = apexSdk->registerPhysXIndicatorGpuClient();
+ }
+ }
+ }
+
+ //APEX_DEBUG_INFO("Gpu Factory %p", mGpuFactory);
+ if (mGpuFactory.factory != NULL)
+ {
+ return mGpuFactory;
+ }
+ else
+ {
+ APEX_DEBUG_INFO("Gpu Factory could not be created");
+ useCuda = false;
+ }
+ }
+
+ if (!useCuda)
+#else
+ PX_UNUSED(useCuda);
+#endif
+ {
+ if (mCpuFactory.factory == NULL)
+ {
+ mCpuFactory = mModule->createClothFactory(NULL);
+ }
+
+ //APEX_DEBUG_INFO("Cpu Factory %p", mCpuFactory.factory);
+ return mCpuFactory;
+ }
+
+#if APEX_CUDA_SUPPORT
+ PX_ALWAYS_ASSERT_MESSAGE("this code path is unreachable, at least it used to be.");
+ return ClothFactory(NULL, NULL);
+#endif
+}
+
+
+
+cloth::Solver* ClothingScene::getClothSolver(bool useCuda)
+{
+ ClothFactory factory(NULL, NULL);
+#if APEX_CUDA_SUPPORT
+ if (useCuda)
+ {
+ factory = mGpuFactory;
+ }
+ else
+#else
+ PX_UNUSED(useCuda);
+#endif
+ {
+ factory = mCpuFactory;
+ }
+
+ PX_ASSERT(factory.factory != NULL);
+ if (factory.factory != NULL)
+ {
+ return mSimulationTask->getSolver(factory);
+ }
+
+ return NULL;
+}
+
+
+
+void ClothingScene::lockScene()
+{
+ mSceneLock.lock();
+
+ if (mSceneRunning == 1)
+ {
+ APEX_INVALID_OPERATION("The scene is running while the scene write lock is being acquired!");
+ PX_ALWAYS_ASSERT();
+ }
+}
+
+
+
+void ClothingScene::unlockScene()
+{
+ mSceneLock.unlock();
+}
+
+
+
+void ClothingScene::setSceneRunning(bool on)
+{
+#ifndef _DEBUG
+ int32_t newValue;
+ if (on)
+ {
+ APEX_CHECK_STAT_TIMER("--------- Start ClothingSimulationTime");
+ mClothingSimulationTime.getElapsedSeconds();
+
+ newValue = nvidia::atomicIncrement(&mSceneRunning);
+ }
+ else
+ {
+ StatValue dataVal;
+ dataVal.Float = (float)(1000.0f * mClothingSimulationTime.getElapsedSeconds());
+ APEX_CHECK_STAT_TIMER("--------- Stop ClothingSimulationTime");
+ mApexScene->setApexStatValue(SceneIntl::ClothingSimulationTime, dataVal);
+
+ // Warn if simulation time was bigger than timestep for 10 or more consecutive frames
+ float simulatedTime = 1000.0f * mApexScene->getElapsedTime();
+ if (simulatedTime < dataVal.Float)
+ {
+ mFramesCount++;
+ mSimulatedTime += simulatedTime;
+ mTimestep += dataVal.Float;
+ }
+
+ if (mFramesCount >= 10)
+ {
+ float averageSimulatedTime = mSimulatedTime / (float)mFramesCount;
+ float averageTimestep = mTimestep / (float)mFramesCount;
+ APEX_DEBUG_WARNING("Cloth complexity in scene is too high to be simulated in real time for 10 consecutive frames. (Average Delta Time: %f ms, Average Simulation Time: %f ms)",
+ averageSimulatedTime, averageTimestep);
+ mFramesCount = 0;
+ mSimulatedTime = 0.f;
+ mTimestep = 0.f;
+ }
+
+ newValue = nvidia::atomicDecrement(&mSceneRunning);
+ }
+
+ if (newValue != (on ? 1 : 0))
+ {
+ APEX_INTERNAL_ERROR("scene running state was not tracked properly!: on = %s, prevValue = %d", on ? "true" : "false", newValue);
+ }
+#else
+ PX_UNUSED(on);
+#endif
+}
+
+
+
+void ClothingScene::embeddedPostSim()
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->startFetchTasks();
+ }
+}
+
+
+
+ClothingRenderProxyImpl* ClothingScene::getRenderProxy(RenderMeshAssetIntl* rma, bool useFallbackSkinning, bool useCustomVertexBuffer, const HashMap<uint32_t, ApexSimpleString>& overrideMaterials, const PxVec3* morphTargetNewPositions, const uint32_t* morphTargetVertexOffsets)
+{
+ if (rma == NULL)
+ {
+ return NULL;
+ }
+
+ ClothingRenderProxyImpl* renderProxy = NULL;
+
+
+ mRenderProxiesLock.lock();
+ Array<ClothingRenderProxyImpl*>& renderProxies = mRenderProxies[rma];
+ for (uint32_t i = 0; i < renderProxies.size(); ++i)
+ {
+ ClothingRenderProxyImpl* proxyInPool = renderProxies[i];
+ if (
+ proxyInPool->getTimeInPool() > 0 && // proxy is available
+ useFallbackSkinning == proxyInPool->usesFallbackSkinning() &&
+ useCustomVertexBuffer == proxyInPool->usesCustomVertexBuffer() &&
+ morphTargetNewPositions == proxyInPool->getMorphTargetBuffer() &&
+ proxyInPool->overrideMaterialsEqual(overrideMaterials)
+ )
+ {
+ renderProxy = proxyInPool;
+ break;
+ }
+ }
+
+ // no corresponding proxy in pool, so create one
+ if (renderProxy == NULL)
+ {
+ renderProxy = PX_NEW(ClothingRenderProxyImpl)(rma, useFallbackSkinning, useCustomVertexBuffer, overrideMaterials, morphTargetNewPositions, morphTargetVertexOffsets, this);
+ renderProxies.pushBack(renderProxy);
+ }
+
+ renderProxy->setTimeInPool(0);
+ mRenderProxiesLock.unlock();
+
+ return renderProxy;
+}
+
+
+
+void ClothingScene::tickRenderProxies()
+{
+ PX_PROFILE_ZONE("ClothingScene::tickRenderProxies", GetInternalApexSDK()->getContextId());
+ mRenderProxiesLock.lock();
+
+ for(HashMap<RenderMeshAssetIntl*, Array<ClothingRenderProxyImpl*> >::Iterator iter = mRenderProxies.getIterator(); !iter.done(); ++iter)
+ {
+ Array<ClothingRenderProxyImpl*>& renderProxies = iter->second;
+
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ uint32_t timeInPool = renderProxies[(uint32_t)i]->getTimeInPool();
+
+ if (timeInPool > 0)
+ {
+ if (timeInPool > mModule->getMaxTimeRenderProxyInPool() + 1) // +1 because we add them with time 1
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ renderProxies.replaceWithLast((uint32_t)i);
+ }
+ else
+ {
+ renderProxies[(uint32_t)i]->setTimeInPool(timeInPool+1);
+ }
+ }
+ }
+ }
+
+ mRenderProxiesLock.unlock();
+}
+
+}
+} // namespace nvidia
+