JobSystemWithBarrier.h 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Core/JobSystem.h>
  6. #include <Jolt/Core/Semaphore.h>
  7. JPH_NAMESPACE_BEGIN
  8. /// Implementation of the Barrier class for a JobSystem
  9. ///
  10. /// This class can be used to make it easier to create a new JobSystem implementation that integrates with your own job system.
  11. /// It will implement all functionality relating to barriers, so the only functions that are left to be implemented are:
  12. ///
  13. /// * JobSystem::GetMaxConcurrency
  14. /// * JobSystem::CreateJob
  15. /// * JobSystem::FreeJob
  16. /// * JobSystem::QueueJob/QueueJobs
  17. ///
  18. /// See instructions in JobSystem for more information on how to implement these.
  19. class JPH_EXPORT JobSystemWithBarrier : public JobSystem
  20. {
  21. public:
  22. JPH_OVERRIDE_NEW_DELETE
  23. /// Constructs barriers
  24. /// @see JobSystemWithBarrier::Init
  25. explicit JobSystemWithBarrier(uint inMaxBarriers);
  26. JobSystemWithBarrier() = default;
  27. virtual ~JobSystemWithBarrier() override;
  28. /// Initialize the barriers
  29. /// @param inMaxBarriers Max number of barriers that can be allocated at any time
  30. void Init(uint inMaxBarriers);
  31. // See JobSystem
  32. virtual Barrier * CreateBarrier() override;
  33. virtual void DestroyBarrier(Barrier *inBarrier) override;
  34. virtual void WaitForJobs(Barrier *inBarrier) override;
  35. private:
  36. class BarrierImpl : public Barrier
  37. {
  38. public:
  39. JPH_OVERRIDE_NEW_DELETE
  40. /// Constructor
  41. BarrierImpl();
  42. virtual ~BarrierImpl() override;
  43. // See Barrier
  44. virtual void AddJob(const JobHandle &inJob) override;
  45. virtual void AddJobs(const JobHandle *inHandles, uint inNumHandles) override;
  46. /// Check if there are any jobs in the job barrier
  47. inline bool IsEmpty() const { return mJobReadIndex == mJobWriteIndex; }
  48. /// Wait for all jobs in this job barrier, while waiting, execute jobs that are part of this barrier on the current thread
  49. void Wait();
  50. /// Flag to indicate if a barrier has been handed out
  51. atomic<bool> mInUse { false };
  52. protected:
  53. /// Called by a Job to mark that it is finished
  54. virtual void OnJobFinished(Job *inJob) override;
  55. /// Jobs queue for the barrier
  56. static constexpr uint cMaxJobs = 2048;
  57. static_assert(IsPowerOf2(cMaxJobs)); // We do bit operations and require max jobs to be a power of 2
  58. atomic<Job *> mJobs[cMaxJobs]; ///< List of jobs that are part of this barrier, nullptrs for empty slots
  59. alignas(JPH_CACHE_LINE_SIZE) atomic<uint> mJobReadIndex { 0 }; ///< First job that could be valid (modulo cMaxJobs), can be nullptr if other thread is still working on adding the job
  60. alignas(JPH_CACHE_LINE_SIZE) atomic<uint> mJobWriteIndex { 0 }; ///< First job that can be written (modulo cMaxJobs)
  61. atomic<int> mNumToAcquire { 0 }; ///< Number of times the semaphore has been released, the barrier should acquire the semaphore this many times (written at the same time as mJobWriteIndex so ok to put in same cache line)
  62. Semaphore mSemaphore; ///< Semaphore used by finishing jobs to signal the barrier that they're done
  63. };
  64. /// Array of barriers (we keep them constructed all the time since constructing a semaphore/mutex is not cheap)
  65. uint mMaxBarriers = 0; ///< Max amount of barriers
  66. BarrierImpl * mBarriers = nullptr; ///< List of the actual barriers
  67. };
  68. JPH_NAMESPACE_END