Просмотр исходного кода

Updates in visibility determination
- Moving the containers to new class
- Making the algothithm multithreaded

Panagiotis Christopoulos Charitos 14 лет назад
Родитель
Сommit
aa24bf2aa9

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
build/debug/Makefile


+ 2 - 0
src/Core/App.cpp

@@ -13,6 +13,7 @@
 #include "Input.h"
 #include "Logger.h"
 #include "Globals.h"
+#include "JobManager.h"
 
 
 //======================================================================================================================
@@ -107,6 +108,7 @@ void App::init(int argc, char* argv[])
 
 	initWindow();
 	initRenderer();
+	JobManagerSingleton::getInstance().init(4);
 
 	// other
 	activeCam = NULL;

+ 2 - 0
src/Core/Globals.h

@@ -18,5 +18,7 @@ namespace Event {
 typedef Singleton<class Manager> ManagerSingleton;
 }
 
+typedef Singleton<class JobManager> JobManagerSingleton;
+
 
 #endif

+ 6 - 5
src/Core/JobManager.cpp

@@ -32,7 +32,7 @@ void WorkerThread::workingFunc()
 		}
 
 		// Exec
-		job(id, jobParams);
+		job(jobParams, *this);
 
 		// Nullify
 		{
@@ -46,14 +46,15 @@ void WorkerThread::workingFunc()
 
 
 //======================================================================================================================
-// Constructor                                                                                                         =
+// init                                                                                                                =
 //======================================================================================================================
-JobManager::JobManager(uint threadsNum):
-	barrier(threadsNum + 1)
+void JobManager::init(uint threadsNum)
 {
+	barrier.reset(new boost::barrier(threadsNum + 1));
+
 	for(uint i = 0; i < threadsNum; i++)
 	{
-		workers.push_back(new WorkerThread(i, &barrier));
+		workers.push_back(new WorkerThread(i, *this, barrier.get()));
 	}
 }
 

+ 29 - 10
src/Core/JobManager.h

@@ -3,16 +3,27 @@
 
 #include <boost/thread.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/scoped_ptr.hpp>
+#include "Accessors.h"
 
 
-/// @todo
+class JobManager;
+
+
+/// The thread that executes a job
 class WorkerThread
 {
 	public:
-		typedef void (*JobCallback)(uint jobId, void*);
+		typedef void (*JobCallback)(void*, const WorkerThread&);
 
 		/// Constructor
-		WorkerThread(int id, boost::barrier* barrier);
+		WorkerThread(int id, const JobManager& jobManager, boost::barrier* barrier);
+
+		/// @name Accessors
+		/// @{
+		GETTER_R(uint, id, getId)
+		const JobManager& getJobManager() const {return jobManager;}
+		/// @}
 
 		/// Assign new job to the thread
 		void assignNewJob(JobCallback job, void* jobParams);
@@ -25,6 +36,7 @@ class WorkerThread
 		boost::barrier* barrier;
 		JobCallback job; ///< Its NULL if there are no pending jobs
 		void* jobParams;
+		const JobManager& jobManager; ///< Know your father and pass him to the jobs
 
 		/// Start thread
 		void start();
@@ -34,10 +46,11 @@ class WorkerThread
 };
 
 
-inline WorkerThread::WorkerThread(int id_, boost::barrier* barrier_):
+inline WorkerThread::WorkerThread(int id_, const JobManager& jobManager_, boost::barrier* barrier_):
 	id(id_),
 	barrier(barrier_),
-	job(NULL)
+	job(NULL),
+	jobManager(jobManager_)
 {
 	start();
 }
@@ -53,8 +66,14 @@ inline void WorkerThread::start()
 class JobManager
 {
 	public:
-		/// Constructor
-		JobManager(uint threadsNum);
+		/// Default constructor
+		JobManager() {}
+
+		/// Constructor #2
+		JobManager(uint threadsNum) {init(threadsNum);}
+
+		/// Init the manager
+		void init(uint threadsNum);
 
 		/// Assign a job to a working thread
 		void assignNewJob(uint threadId, WorkerThread::JobCallback job, void* jobParams);
@@ -65,8 +84,8 @@ class JobManager
 		uint getThreadsNum() const {return workers.size();}
 
 	private:
-		boost::ptr_vector<WorkerThread> workers;
-		boost::barrier barrier;
+		boost::ptr_vector<WorkerThread> workers; ///< Worker threads
+		boost::scoped_ptr<boost::barrier> barrier; ///< Synchronization barrier
 };
 
 
@@ -78,7 +97,7 @@ inline void JobManager::assignNewJob(uint threadId, WorkerThread::JobCallback jo
 
 inline void JobManager::waitForAllJobsToFinish()
 {
-	barrier.wait();
+	barrier->wait();
 }
 
 

+ 1 - 1
src/Renderer/Is.cpp

@@ -206,7 +206,7 @@ void Is::spotLightPass(const SpotLight& light)
 
 		float dist = seg.testPlane(plane);
 
-		sm.run(light.getCamera(), dist);
+		sm.run(light, dist);
 
 		// restore the IS FBO
 		fbo.bind();

+ 16 - 3
src/Renderer/Sm.cpp

@@ -5,6 +5,8 @@
 #include "Scene.h"
 #include "LightRsrc.h"
 #include "Camera.h"
+#include "Light.h"
+#include "SpotLight.h"
 #include "RendererInitializer.h"
 
 
@@ -91,7 +93,7 @@ void Sm::initLevel(uint resolution, float distance, bool bilinear, Level& level)
 //======================================================================================================================
 // run                                                                                                                 =
 //======================================================================================================================
-void Sm::run(const Camera& cam, float distance)
+void Sm::run(const Light& light, float distance)
 {
 	if(!enabled)
 	{
@@ -131,9 +133,20 @@ void Sm::run(const Camera& cam, float distance)
 	glEnable(GL_POLYGON_OFFSET_FILL);
 
 	// render all
-	BOOST_FOREACH(const RenderableNode* node, cam.getVisibleMsRenderableNodes())
+	BOOST_FOREACH(const RenderableNode* node, light.getVisibleMsRenderableNodes())
 	{
-		r.getSceneDrawer().renderRenderableNode(*node, cam, SceneDrawer::RPT_DEPTH);
+		switch(light.getType())
+		{
+			case Light::LT_SPOT:
+			{
+				const SpotLight& sl = static_cast<const SpotLight&>(light);
+				r.getSceneDrawer().renderRenderableNode(*node, sl.getCamera(), SceneDrawer::RPT_DEPTH);
+				break;
+			}
+
+			default:
+				ASSERT(0);
+		}
 	}
 
 	// restore GL

+ 3 - 3
src/Renderer/Sm.h

@@ -8,7 +8,7 @@
 #include "VisibilityTester.h"
 
 
-class Camera;
+class Light;
 
 
 /// Shadowmapping pass
@@ -29,9 +29,9 @@ class Sm: private RenderingPass
 		void init(const RendererInitializer& initializer);
 
 		/// Render the scene only with depth and store the result in the shadowMap
-		/// @param[in] cam The light camera
+		/// @param[in] light The light
 		/// @param[in] distance The distance between the viewers camera and the light
-		void run(const Camera& cam, float distance);
+		void run(const Light& light, float distance);
 
 	private:
 		/// The shadowmap levels of detail

+ 3 - 15
src/Scene/Cameras/Camera.h

@@ -8,6 +8,7 @@
 #include "Collision.h"
 #include "SceneNode.h"
 #include "Accessors.h"
+#include "VisibilityInfo.h"
 
 
 class RenderableNode;
@@ -16,7 +17,7 @@ class PointLight;
 
 
 /// Camera SceneNode
-class Camera: public SceneNode
+class Camera: public SceneNode, public VisibilityInfo
 {
 	public:
 		enum CameraType
@@ -55,11 +56,6 @@ class Camera: public SceneNode
 		/// See the declaration of invProjectionMat for info
 		const Mat4& getInvProjectionMatrix() const {return invProjectionMat;}
 
-		GETTER_RW(std::deque<const RenderableNode*>, msRenderableNodes, getVisibleMsRenderableNodes)
-		GETTER_RW(std::deque<const RenderableNode*>, bsRenderableNodes, getVisibleBsRenderableNodes)
-		GETTER_RW(Vec<const PointLight*>, pointLights, getVisiblePointLights)
-		GETTER_RW(Vec<SpotLight*>, spotLights, getVisibleSpotLights)
-
 		const Plane& getWSpaceFrustumPlane(FrustrumPlanes id) const {return wspaceFrustumPlanes[id];}
 		/// @}
 
@@ -110,21 +106,13 @@ class Camera: public SceneNode
 		Mat4 invProjectionMat;
 		/// @}
 
-		/// @name Visible nodes. They are in separate containers for faster shorting
-		/// @{
-		std::deque<const RenderableNode*> msRenderableNodes;
-		std::deque<const RenderableNode*> bsRenderableNodes;
-		Vec<const PointLight*> pointLights;
-		Vec<SpotLight*> spotLights;
-		/// @}
-
 		/// Calculate projectionMat and invProjectionMat
 		virtual void calcProjectionMatrix() = 0;
 		virtual void calcLSpaceFrustumPlanes() = 0;
 		void updateViewMatrix();
 		void updateWSpaceFrustumPlanes();
 
-		/// @todo
+		/// Get the edge points of the camera
 		virtual void getExtremePoints(Vec3* pointsArr, uint& pointsNum) const = 0;
 };
 

+ 2 - 1
src/Scene/Lights/Light.h

@@ -5,6 +5,7 @@
 #include "SceneNode.h"
 #include "RsrcPtr.h"
 #include "LightRsrc.h"
+#include "VisibilityInfo.h"
 
 
 /// Light scene node. It can be spot or point
@@ -23,7 +24,7 @@
 /// Specular intensity of light:    Sl
 /// Specular intensity of material: Sm
 /// @endcode
-class Light: public SceneNode
+class Light: public SceneNode, public VisibilityInfo
 {
 	public:
 		enum LightType

+ 37 - 0
src/Scene/VisibilityInfo.h

@@ -0,0 +1,37 @@
+#ifndef VISIBILITY_INFO_H
+#define VISIBILITY_INFO_H
+
+#include <deque>
+#include "Vec.h"
+#include "Accessors.h"
+
+
+class RenderableNode;
+class PointLight;
+class SpotLight;
+
+
+/// The class contains scene nodes, categorized by type, that are visible.
+/// The nodes are in separate containers for faster shorting
+class VisibilityInfo
+{
+	public:
+		/// @name Accessors
+		/// @{
+		GETTER_RW(std::deque<const RenderableNode*>, msRenderableNodes, getVisibleMsRenderableNodes)
+		GETTER_RW(std::deque<const RenderableNode*>, bsRenderableNodes, getVisibleBsRenderableNodes)
+		GETTER_RW(Vec<const PointLight*>, pointLights, getVisiblePointLights)
+		GETTER_RW(Vec<SpotLight*>, spotLights, getVisibleSpotLights)
+		/// @}
+
+	private:
+		std::deque<const RenderableNode*> msRenderableNodes;
+		std::deque<const RenderableNode*> bsRenderableNodes;
+		Vec<const PointLight*> pointLights; ///< Used only for non-light cameras
+		Vec<SpotLight*> spotLights; ///< Used only for non-light cameras
+};
+
+
+#endif
+
+

+ 151 - 17
src/Scene/VisibilityTester.cpp

@@ -8,6 +8,7 @@
 #include "Sphere.h"
 #include "PointLight.h"
 #include "SpotLight.h"
+#include "JobManager.h"
 
 
 //======================================================================================================================
@@ -83,14 +84,14 @@ void VisibilityTester::test(Camera& cam)
 	//
 	// Get the renderables for the main cam
 	//
-	getRenderableNodes(false, cam);
+	getRenderableNodes(false, cam, cam);
 
 	//
 	// For every spot light camera collect the renderable nodes
 	//
 	BOOST_FOREACH(SpotLight* spot, cam.getVisibleSpotLights())
 	{
-		getRenderableNodes(true, spot->getCamera());
+		getRenderableNodes(true, spot->getCamera(), *spot);
 	}
 }
 
@@ -108,18 +109,29 @@ bool VisibilityTester::test(const Type& tested, const Camera& cam)
 //======================================================================================================================
 // getRenderableNodes                                                                                                  =
 //======================================================================================================================
-void VisibilityTester::getRenderableNodes(bool skipShadowless, Camera& cam)
+void VisibilityTester::getRenderableNodes(bool skipShadowless_, const Camera& cam_, VisibilityInfo& storage)
 {
-	cam.getVisibleMsRenderableNodes().clear();
-	cam.getVisibleBsRenderableNodes().clear();
+	cam = &cam_;
+	skipShadowless = skipShadowless_;
+	visibilityInfo = &storage;
 
+	storage.getVisibleMsRenderableNodes().clear();
+	storage.getVisibleBsRenderableNodes().clear();
+
+	for(uint i = 0; i < JobManagerSingleton::getInstance().getThreadsNum(); i++)
+	{
+		JobManagerSingleton::getInstance().assignNewJob(i, getRenderableNodesJobCallback, this);
+	}
+	JobManagerSingleton::getInstance().waitForAllJobsToFinish();
+
+	/*
 	//
 	// ModelNodes
 	//
 	BOOST_FOREACH(ModelNode* node, scene.getModelNodes())
 	{
 		// Skip if the ModeNode is not visible
-		if(!test(*node, cam))
+		if(!test(*node, *cam))
 		{
 			continue;
 		}
@@ -136,15 +148,15 @@ void VisibilityTester::getRenderableNodes(bool skipShadowless, Camera& cam)
 			}
 
 			// Test if visible by main camera
-			if(test(*modelPatchNode, cam))
+			if(test(*modelPatchNode, *cam))
 			{
 				if(modelPatchNode->getCpMtl().renderInBlendingStage())
 				{
-					cam.getVisibleBsRenderableNodes().push_back(modelPatchNode);
+					storage.getVisibleBsRenderableNodes().push_back(modelPatchNode);
 				}
 				else
 				{
-					cam.getVisibleMsRenderableNodes().push_back(modelPatchNode);
+					storage.getVisibleMsRenderableNodes().push_back(modelPatchNode);
 				}
 				modelPatchNode->setVisible(true);
 			}
@@ -157,7 +169,7 @@ void VisibilityTester::getRenderableNodes(bool skipShadowless, Camera& cam)
 	BOOST_FOREACH(SkinNode* node, scene.getSkinNodes())
 	{
 		// Skip if the SkinNode is not visible
-		if(!test(*node, cam))
+		if(!test(*node, *cam))
 		{
 			continue;
 		}
@@ -175,22 +187,144 @@ void VisibilityTester::getRenderableNodes(bool skipShadowless, Camera& cam)
 
 			if(patchNode->getCpMtl().renderInBlendingStage())
 			{
-				cam.getVisibleBsRenderableNodes().push_back(patchNode);
+				storage.getVisibleBsRenderableNodes().push_back(patchNode);
 			}
 			else
 			{
-				cam.getVisibleMsRenderableNodes().push_back(patchNode);
+				storage.getVisibleMsRenderableNodes().push_back(patchNode);
 			}
 			patchNode->setVisible(true);
 		}
-	}
+	}*/
 
 	//
 	// Sort the renderables from closest to the camera to the farthest
 	//
-	std::sort(cam.getVisibleMsRenderableNodes().begin(), cam.getVisibleMsRenderableNodes().end(),
-	          CmpDistanceFromOrigin(cam.getWorldTransform().getOrigin()));
-	std::sort(cam.getVisibleBsRenderableNodes().begin(), cam.getVisibleBsRenderableNodes().end(),
-	          CmpDistanceFromOrigin(cam.getWorldTransform().getOrigin()));
+	std::sort(storage.getVisibleMsRenderableNodes().begin(), storage.getVisibleMsRenderableNodes().end(),
+	          CmpDistanceFromOrigin(cam->getWorldTransform().getOrigin()));
+	std::sort(storage.getVisibleBsRenderableNodes().begin(), storage.getVisibleBsRenderableNodes().end(),
+	          CmpDistanceFromOrigin(cam->getWorldTransform().getOrigin()));
 }
 
+
+//======================================================================================================================
+// getRenderableNodesJobCallback                                                                                       =
+//======================================================================================================================
+void VisibilityTester::getRenderableNodesJobCallback(void* args, const WorkerThread& workerThread)
+{
+	uint id = workerThread.getId();
+	uint threadsNum = workerThread.getJobManager().getThreadsNum();
+	VisibilityTester* visTester = reinterpret_cast<VisibilityTester*>(args);
+	Scene& scene = visTester->scene;
+
+	uint count, from, to;
+	size_t nodesSize;
+
+	//
+	// ModelNodes
+	//
+	nodesSize = scene.getModelNodes().size();
+	count = nodesSize / threadsNum;
+	from = count * id;
+	to = count * (id + 1);
+
+	if(id == threadsNum - 1) // The last job will get the rest
+	{
+		to = nodesSize;
+	}
+
+
+	Scene::Types<ModelNode>::Iterator it = scene.getModelNodes().begin() + from;
+	while(it != scene.getModelNodes().begin() + to)
+	{
+		ASSERT(it != scene.getModelNodes().end());
+		ModelNode* node = *it;
+
+		// Skip if the ModeNode is not visible
+		if(!test(*node, *visTester->cam))
+		{
+			continue;
+		}
+
+		node->setVisible(true);
+
+		// If visible test every patch individually
+		BOOST_FOREACH(ModelPatchNode* modelPatchNode, node->getModelPatchNodes())
+		{
+			// Skip shadowless
+			if(visTester->skipShadowless && !modelPatchNode->getCpMtl().castsShadow())
+			{
+				continue;
+			}
+
+			// Test if visible by main camera
+			if(test(*modelPatchNode, *visTester->cam))
+			{
+				if(modelPatchNode->getCpMtl().renderInBlendingStage())
+				{
+					boost::mutex::scoped_lock lock(visTester->bsRenderableNodesMtx);
+					visTester->visibilityInfo->getVisibleBsRenderableNodes().push_back(modelPatchNode);
+				}
+				else
+				{
+					boost::mutex::scoped_lock lock(visTester->msRenderableNodesMtx);
+					visTester->visibilityInfo->getVisibleMsRenderableNodes().push_back(modelPatchNode);
+				}
+				modelPatchNode->setVisible(true);
+			}
+		}
+	}
+
+
+	//
+	// SkinNodes
+	//
+	{
+		nodesSize = scene.getSkinNodes().size();
+		count = nodesSize / threadsNum;
+		from = count * id;
+		to = count * (id + 1);
+
+		if(id == threadsNum - 1) // The last job will get the rest
+		{
+			to = nodesSize;
+		}
+
+		Scene::Types<SkinNode>::Iterator it = scene.getSkinNodes().begin() + from;
+		while(it != scene.getSkinNodes().begin() + to)
+		{
+			ASSERT(it != scene.getSkinNodes().end());
+			SkinNode* node = *it;
+
+			// Skip if the SkinNode is not visible
+			if(!test(*node, *visTester->cam))
+			{
+				continue;
+			}
+
+			node->setVisible(true);
+
+			// Put all the patches into the visible container
+			BOOST_FOREACH(SkinPatchNode* patchNode, node->getPatcheNodes())
+			{
+				// Skip shadowless
+				if(visTester->skipShadowless && !patchNode->getCpMtl().castsShadow())
+				{
+					continue;
+				}
+
+				if(patchNode->getCpMtl().renderInBlendingStage())
+				{
+					boost::mutex::scoped_lock lock(visTester->bsRenderableNodesMtx);
+					visTester->visibilityInfo->getVisibleBsRenderableNodes().push_back(patchNode);
+				}
+				else
+				{
+					boost::mutex::scoped_lock lock(visTester->msRenderableNodesMtx);
+					visTester->visibilityInfo->getVisibleMsRenderableNodes().push_back(patchNode);
+				}
+				patchNode->setVisible(true);
+			}
+		}
+	}
+}

+ 22 - 3
src/Scene/VisibilityTester.h

@@ -2,6 +2,7 @@
 #define VISIBILITY_TESTER_H
 
 #include <deque>
+#include <boost/thread.hpp>
 #include "Accessors.h"
 #include "Math.h"
 
@@ -12,6 +13,8 @@ class RenderableNode;
 class SpotLight;
 class PointLight;
 class SceneNode;
+class VisibilityInfo;
+class WorkerThread;
 
 
 /// Performs visibility determination tests and fills a few containers with the visible scene nodes
@@ -39,14 +42,30 @@ class VisibilityTester
 
 		Scene& scene; ///< Know your father
 
+		/// @name Needed by getRenderableNodesJobCallback
+		/// The vars of this group are needed by the static getRenderableNodesJobCallback and kept here so it can
+		/// access them
+		/// @{
+		const Camera* cam;
+		bool skipShadowless;
+		VisibilityInfo* visibilityInfo;
+		boost::mutex msRenderableNodesMtx;
+		boost::mutex bsRenderableNodesMtx;
+		/// @}
+
 		/// Test a node against the camera frustum
 		template<typename Type>
 		static bool test(const Type& tested, const Camera& cam);
 
 		/// Get renderable nodes for a given camera
-		/// @param skipShadowless Skip shadowless nodes. If the cam is a light cam
-		/// @param cam The camera to test and gather renderable nodes
-		void getRenderableNodes(bool skipShadowless, Camera& cam);
+		/// @param[in] skipShadowless Skip shadowless nodes. If the cam is a light cam
+		/// @param[in] cam The camera to test and gather renderable nodes
+		/// @param[out] storage The VisibilityInfo of where we will store the visible nodes
+		void getRenderableNodes(bool skipShadowless, const Camera& cam, VisibilityInfo& storage);
+
+		/// This static method will be fed into the JobManager
+		/// @param data This is actually a pointer to VisibilityTester
+		static void getRenderableNodesJobCallback(void* data, const WorkerThread& workerThread);
 };
 
 

Некоторые файлы не были показаны из-за большого количества измененных файлов