diff options
| author | mtamis <[email protected]> | 2017-02-28 18:24:59 +0100 |
|---|---|---|
| committer | mtamis <[email protected]> | 2017-02-28 18:24:59 +0100 |
| commit | 5581909a4d19db97304449f66404ff99a0429d3f (patch) | |
| tree | a90f7eb85c095a8aba45cf5e909c82c1cdbed77d /NvCloth/samples/SampleBase/utils/JobManager.h | |
| parent | Fix cmake visual studio project generation (locate_gw_root.bat) (diff) | |
| download | nvcloth-5581909a4d19db97304449f66404ff99a0429d3f.tar.xz nvcloth-5581909a4d19db97304449f66404ff99a0429d3f.zip | |
Add visual samples.
Diffstat (limited to 'NvCloth/samples/SampleBase/utils/JobManager.h')
| -rw-r--r-- | NvCloth/samples/SampleBase/utils/JobManager.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/NvCloth/samples/SampleBase/utils/JobManager.h b/NvCloth/samples/SampleBase/utils/JobManager.h new file mode 100644 index 0000000..648fa33 --- /dev/null +++ b/NvCloth/samples/SampleBase/utils/JobManager.h @@ -0,0 +1,175 @@ +/* +* Copyright (c) 2008-2017, 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. +*/ + +#pragma once + +#include <foundation/PxErrorCallback.h> +#include <regex> +#include "CallbackImplementations.h" +#include <mutex> +#include <thread> +#include <condition_variable> + +#include <foundation/PxVec4.h> +#include <foundation/PxVec3.h> +#include <vector> +#include <queue> +#include <atomic> + +#include <task/PxTaskManager.h> +#include <task/PxTask.h> + +namespace nv +{ +namespace cloth +{ +class Solver; +} +} + +///Dummy task that can be used as end node in a task graph. +class DummyTask : public physx::PxTask +{ +public: + DummyTask() { mFinished = false; mTm = nullptr; } + DummyTask(physx::PxTaskManager* tm) { mFinished = false; mTm = tm; mTm->submitUnnamedTask(*this); } + ~DummyTask() { mTm = nullptr; } //Way to catch race conditions. Will usually crash on nullptr if the task gets deleted before the taskmanager is done with it. + + virtual void run() override { } + virtual void release() override { physx::PxTask::release(); mFinished = true; mWaitEvent.notify_all(); } + virtual const char* getName() const override { return "DummyTask"; } + + void Reset(physx::PxTaskManager* tm) { mFinished = false; mTm = tm; mTm->submitUnnamedTask(*this); } + + ///Use Wait to block the calling thread until this task is finished and save to delete + void Wait() + { + std::mutex eventLock; + std::unique_lock<std::mutex> lock(eventLock); + while (!mFinished) { mWaitEvent.wait(lock); } + } + +private: + std::condition_variable mWaitEvent; + bool mFinished; +}; + +class CpuDispatcher : public physx::PxCpuDispatcher +{ + virtual void submitTask(physx::PxBaseTask& task) + { + task.run(); + task.release(); + } + virtual uint32_t getWorkerCount() const { return 1; } +}; + + +class JobManager; +class Job +{ +public: + Job() = default; + Job(const Job&); + void Initialize(JobManager* parent, std::function<void(Job*)> function = std::function<void(Job*)>(), int refcount = 1); + void Reset(int refcount = 1); //Call this before reusing a job that doesn't need to be reinitialized + void Execute(); + void AddReference(); + void RemoveReference(); + void Wait(); //Block until job is finished +private: + virtual void ExecuteInternal() {} + + std::function<void(Job*)> mFunction; + JobManager* mParent; + std::atomic_int mRefCount; + + bool mFinished; + std::mutex mFinishedLock; + std::condition_variable mFinishedEvent; +}; + +class JobManager +{ +public: + JobManager() + { + mWorkerCount = 8; + mWorkerThreads = new std::thread[mWorkerCount]; + mQuit = false; + + for(int i = 0; i < mWorkerCount; i++) + mWorkerThreads[i] = std::thread(JobManager::WorkerEntryPoint, this); + } + ~JobManager() + { + if(!mQuit) + Quit(); + } + + void Quit() + { + std::unique_lock<std::mutex> lock(mJobQueueLock); + mQuit = true; + lock.unlock(); + mJobQueueEvent.notify_all(); + for(int i = 0; i < mWorkerCount; i++) + { + mWorkerThreads[i].join(); + } + delete[] mWorkerThreads; + } + + template <int count, typename F> + void ParallelLoop(F const& function) + { + /*for(int i = 0; i < count; i++) + function(i);*/ + Job finalJob; + finalJob.Initialize(this, std::function<void(Job*)>(), count); + Job jobs[count]; + for(int j = 0; j < count; j++) + { + jobs[j].Initialize(this, [j, &finalJob, function](Job*) {function(j); finalJob.RemoveReference(); }); + jobs[j].RemoveReference(); + } + finalJob.Wait(); + } + + static void WorkerEntryPoint(JobManager* parrent); +private: + friend class Job; + void Submit(Job* job); + + int mWorkerCount; + std::thread* mWorkerThreads; + + std::mutex mJobQueueLock; + std::queue<Job*> mJobQueue; + std::condition_variable mJobQueueEvent; + bool mQuit; +}; + +class MultithreadedSolverHelper +{ +public: + void Initialize(nv::cloth::Solver* solver, JobManager* jobManager); + void StartSimulation(float dt); + void WaitForSimulation(); +private: + Job mStartSimulationJob; + Job mEndSimulationJob; + std::vector<Job> mSimulationChunkJobs; + + float mDt; + + nv::cloth::Solver* mSolver; + JobManager* mJobManager; +}; |