Browse Source

Added single threaded job system (#588)

Meant for debugging purposes, used by determinism validation in SamplesApp.
Jorrit Rouwe 2 years ago
parent
commit
687aefccce

+ 65 - 0
Jolt/Core/JobSystemSingleThreaded.cpp

@@ -0,0 +1,65 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2023 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#include <Jolt/Jolt.h>
+
+#include <Jolt/Core/JobSystemSingleThreaded.h>
+
+JPH_NAMESPACE_BEGIN
+
+void JobSystemSingleThreaded::Init(uint inMaxJobs)
+{
+	mJobs.Init(inMaxJobs, inMaxJobs);
+}
+
+JobHandle JobSystemSingleThreaded::CreateJob(const char *inJobName, ColorArg inColor, const JobFunction &inJobFunction, uint32 inNumDependencies)
+{
+	// Construct an object
+	uint32 index = mJobs.ConstructObject(inJobName, inColor, this, inJobFunction, inNumDependencies);
+	JPH_ASSERT(index != AvailableJobs::cInvalidObjectIndex);
+	Job *job = &mJobs.Get(index);
+	
+	// Construct handle to keep a reference, the job is queued below and will immediately complete
+	JobHandle handle(job);
+	
+	// If there are no dependencies, queue the job now
+	if (inNumDependencies == 0)
+		QueueJob(job);
+
+	// Return the handle
+	return handle;
+}
+
+void JobSystemSingleThreaded::FreeJob(Job *inJob)
+{
+	mJobs.DestructObject(inJob);
+}
+
+void JobSystemSingleThreaded::QueueJob(Job *inJob)
+{
+	inJob->Execute();
+}
+
+void JobSystemSingleThreaded::QueueJobs(Job **inJobs, uint inNumJobs)
+{
+	for (uint i = 0; i < inNumJobs; ++i)
+		QueueJob(inJobs[i]);
+}
+
+JobSystem::Barrier *JobSystemSingleThreaded::CreateBarrier()
+{
+	return &mDummyBarrier;
+}
+
+void JobSystemSingleThreaded::DestroyBarrier(Barrier *inBarrier)
+{
+	// There's nothing to do here, the barrier is just a dummy
+}
+
+void JobSystemSingleThreaded::WaitForJobs(Barrier *inBarrier)
+{
+	// There's nothing to do here, the barrier is just a dummy, we just execute the jobs immediately
+}
+
+JPH_NAMESPACE_END

+ 62 - 0
Jolt/Core/JobSystemSingleThreaded.h

@@ -0,0 +1,62 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2023 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <Jolt/Core/JobSystem.h>
+#include <Jolt/Core/FixedSizeFreeList.h>
+
+JPH_NAMESPACE_BEGIN
+
+/// Implementation of a JobSystem without threads, runs jobs as soon as they are added
+class JPH_EXPORT JobSystemSingleThreaded final : public JobSystem
+{
+public:
+	JPH_OVERRIDE_NEW_DELETE
+
+	/// Constructor
+							JobSystemSingleThreaded() = default;
+	explicit				JobSystemSingleThreaded(uint inMaxJobs)			{ Init(inMaxJobs); }
+
+	/// Initialize the job system
+	/// @param inMaxJobs Max number of jobs that can be allocated at any time
+	void					Init(uint inMaxJobs);
+
+	// See JobSystem
+	virtual int				GetMaxConcurrency() const override				{ return 1; }
+	virtual JobHandle		CreateJob(const char *inName, ColorArg inColor, const JobFunction &inJobFunction, uint32 inNumDependencies = 0) override;
+	virtual Barrier *		CreateBarrier() override;
+	virtual void			DestroyBarrier(Barrier *inBarrier) override;
+	virtual void			WaitForJobs(Barrier *inBarrier) override;
+
+protected:
+	// Dummy implementation of Barrier, all jobs are executed immediately
+	class BarrierImpl : public Barrier
+	{
+	public:
+		JPH_OVERRIDE_NEW_DELETE
+
+		// See Barrier
+		virtual void		AddJob(const JobHandle &inJob) override			{ /* We don't need to track jobs */ }
+		virtual void		AddJobs(const JobHandle *inHandles, uint inNumHandles) override { /* We don't need to track jobs */ }
+
+	protected:
+		/// Called by a Job to mark that it is finished
+		virtual void		OnJobFinished(Job *inJob) override				{ /* We don't need to track jobs */ }
+	};
+
+	// See JobSystem
+	virtual void			QueueJob(Job *inJob) override;
+	virtual void			QueueJobs(Job **inJobs, uint inNumJobs) override;
+	virtual void			FreeJob(Job *inJob) override;
+
+	/// Shared barrier since the barrier implementation does nothing
+	BarrierImpl				mDummyBarrier;
+
+	/// Array of jobs (fixed size)
+	using AvailableJobs = FixedSizeFreeList<Job>;
+	AvailableJobs			mJobs;
+};
+
+JPH_NAMESPACE_END

+ 2 - 0
Jolt/Jolt.cmake

@@ -32,6 +32,8 @@ set(JOLT_PHYSICS_SRC_FILES
 	${JOLT_PHYSICS_ROOT}/Core/IssueReporting.h
 	${JOLT_PHYSICS_ROOT}/Core/IssueReporting.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystem.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystem.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystem.inl
 	${JOLT_PHYSICS_ROOT}/Core/JobSystem.inl
+	${JOLT_PHYSICS_ROOT}/Core/JobSystemSingleThreaded.cpp
+	${JOLT_PHYSICS_ROOT}/Core/JobSystemSingleThreaded.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemThreadPool.cpp
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemThreadPool.cpp
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemThreadPool.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemThreadPool.h
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemWithBarrier.cpp
 	${JOLT_PHYSICS_ROOT}/Core/JobSystemWithBarrier.cpp

+ 3 - 2
Samples/SamplesApp.cpp

@@ -7,6 +7,7 @@
 #include <SamplesApp.h>
 #include <SamplesApp.h>
 #include <Application/EntryPoint.h>
 #include <Application/EntryPoint.h>
 #include <Jolt/Core/JobSystemThreadPool.h>
 #include <Jolt/Core/JobSystemThreadPool.h>
+#include <Jolt/Core/JobSystemSingleThreaded.h>
 #include <Jolt/Core/TempAllocator.h>
 #include <Jolt/Core/TempAllocator.h>
 #include <Jolt/Core/StreamWrapper.h>
 #include <Jolt/Core/StreamWrapper.h>
 #include <Jolt/Geometry/OrientedBox.h>
 #include <Jolt/Geometry/OrientedBox.h>
@@ -360,8 +361,8 @@ SamplesApp::SamplesApp()
 	// Create job system
 	// Create job system
 	mJobSystem = new JobSystemThreadPool(cMaxPhysicsJobs, cMaxPhysicsBarriers, mMaxConcurrentJobs - 1);
 	mJobSystem = new JobSystemThreadPool(cMaxPhysicsJobs, cMaxPhysicsBarriers, mMaxConcurrentJobs - 1);
 
 
-	// Create job system without extra threads for validating
-	mJobSystemValidating = new JobSystemThreadPool(cMaxPhysicsJobs, cMaxPhysicsBarriers, 0);
+	// Create single threaded job system for validating
+	mJobSystemValidating = new JobSystemSingleThreaded(cMaxPhysicsJobs);
 
 
 	{
 	{
 		// Disable allocation checking
 		// Disable allocation checking