Przeglądaj źródła

Finalizing the parallel visibility tester

Panagiotis Christopoulos Charitos 13 lat temu
rodzic
commit
05c09a269c

+ 4 - 1
include/anki/resource/Material.h

@@ -340,7 +340,7 @@ public:
 	/// For sorting
 	Bool operator<(const Material& b) const
 	{
-		return fname < b.fname;
+		return hash < b.hash;
 	}
 
 private:
@@ -365,6 +365,9 @@ private:
 	/// For searching
 	PassLevelToShaderProgramHashMap eSProgs;
 
+	/// Used for sorting
+	std::size_t hash;
+
 	/// One uniform block
 	const ShaderProgramUniformBlock* commonUniformBlock;
 

+ 3 - 3
include/anki/resource/MaterialShaderProgramCreator.h

@@ -10,6 +10,9 @@ class XmlElement;
 /// Creator of shader programs. This class parses between
 /// <shaderProgam></shaderProgram> located inside a <material></material>
 /// and creates the source of a custom program.
+///
+/// @note Be carefull when you change the methods. Create as less unique 
+///       shaders as possible
 class MaterialShaderProgramCreator
 {
 public:
@@ -47,9 +50,6 @@ private:
 
 	Bool enableUniformBlocks;
 
-	/// Used for shorting vectors of strings. Used in std::sort
-	static bool compareStrings(const std::string& a, const std::string& b);
-
 	/// Parse what is within the
 	/// @code <shaderProgram></shaderProgram> @endcode
 	void parseShaderProgramTag(const XmlElement& el);

+ 4 - 0
include/anki/scene/Scene.h

@@ -88,6 +88,10 @@ public:
 	{
 		return nodes.end();
 	}
+	U32 getAllNodesCount() const
+	{
+		return nodes.size();
+	}
 	/// @}
 
 	/// Put a node in the appropriate containers

+ 1 - 0
include/anki/scene/VisibilityTester.h

@@ -22,6 +22,7 @@ class VisibilityInfo
 {
 	friend class VisibilityTester;
 	friend class Octree;
+	friend struct VisibilityTestJob;
 
 public:
 	typedef Vector<SceneNode*> Renderables;

+ 9 - 0
include/anki/util/StringList.h

@@ -19,6 +19,12 @@ public:
 	typedef Base::value_type String; ///< Its string
 	typedef String::value_type Char; ///< Char type
 
+	enum StringListSort
+	{
+		SLS_ASCENDING = 0,
+		SLS_DESCENDING
+	};
+
 	/// Join all the elements into a single big string using a the
 	/// seperator @a sep
 	String join(const Char* sep) const;
@@ -28,6 +34,9 @@ public:
 	/// @return -1 of not found
 	I getIndexOf(const Char* value) const;
 
+	/// Sort the string list
+	void sortAll(const StringListSort method = SLS_ASCENDING);
+
 	/// Split a string using a list of separators (@a sep) and return these
 	/// strings in a string list
 	static Self splitString(const Char* s, const Char sep = ' ',

+ 5 - 0
src/resource/Material.cpp

@@ -269,6 +269,11 @@ void Material::parseMaterialTag(const XmlElement& materialEl)
 	}
 
 	populateVariables(mspc);
+
+	// Create hash
+	//
+	std::hash<std::string> stringHash;
+	hash = stringHash(mspc.getShaderProgramSource());
 }
 
 //==============================================================================

+ 13 - 25
src/resource/MaterialShaderProgramCreator.cpp

@@ -1,6 +1,7 @@
 #include "anki/resource/MaterialShaderProgramCreator.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Exception.h"
+#include "anki/util/StringList.h"
 #include "anki/misc/Xml.h"
 #include "anki/core/Logger.h"
 #include <algorithm>
@@ -34,31 +35,25 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 	} while(shaderEl);
 
 	// Create block
-	if(enableUniformBlocks)
+	if(enableUniformBlocks && inputs.size() > 0)
 	{
 		StringList block;
-		block.push_back("layout(shared, row_major, binding = 0) "
-			"uniform commonBlock\n{");
+		
 		for(Input* in : inputs)
 		{
-			if(in->type == "sampler2D"
-				|| in->const_)
+			if(in->type == "sampler2D" || in->const_)
 			{
 				continue;
 			}
 
 			block.push_back("\tuniform " + in->type + " " + in->name + ";");
 		}
-		block.push_back("};\n");
+		block.sortAll();
 
-		if(block.size() > 2)
-		{
-			source = block.join("\n") + srcLines.join("\n");
-		}
-		else
-		{
-			source = srcLines.join("\n");
-		}
+		std::string blockHead = "layout(shared, row_major, binding = 0) "
+			"uniform commonBlock\n{";
+
+		source = blockHead + block.join("\n") + "};\n" + srcLines.join("\n");
 	}
 	else
 	{
@@ -77,7 +72,7 @@ void MaterialShaderProgramCreator::parseShaderTag(
 
 	// <includes></includes>
 	//
-	Vector<std::string> includeLines;
+	StringList includeLines;
 
 	XmlElement includesEl = shaderEl.getChildElement("includes");
 	XmlElement includeEl = includesEl.getChildElement("include");
@@ -91,7 +86,7 @@ void MaterialShaderProgramCreator::parseShaderTag(
 		includeEl = includeEl.getNextSiblingElement("include");
 	} while(includeEl);
 
-	//std::sort(includeLines.begin(), includeLines.end(), compareStrings);
+	//includeLines.sortAll();
 	srcLines.insert(srcLines.end(), includeLines.begin(), includeLines.end());
 
 	// <inputs></inputs>
@@ -100,7 +95,7 @@ void MaterialShaderProgramCreator::parseShaderTag(
 	if(inputsEl)
 	{
 		// Store the source of the uniform vars
-		Vector<std::string> uniformsLines;
+		StringList uniformsLines;
 	
 		XmlElement inputEl = inputsEl.getChildElement("input");
 		do
@@ -113,7 +108,7 @@ void MaterialShaderProgramCreator::parseShaderTag(
 		} while(inputEl);
 
 		srcLines.push_back("");
-		std::sort(uniformsLines.begin(), uniformsLines.end(), compareStrings);
+		uniformsLines.sortAll();
 		srcLines.insert(srcLines.end(), uniformsLines.begin(),
 			uniformsLines.end());
 	}
@@ -249,11 +244,4 @@ void MaterialShaderProgramCreator::parseOperationTag(
 	srcLines.push_back(line.str());
 }
 
-//==============================================================================
-bool MaterialShaderProgramCreator::compareStrings(
-	const std::string& a, const std::string& b)
-{
-	return a < b;
-}
-
 } // end namespace anki

+ 77 - 60
src/scene/VisibilityTester.cpp

@@ -17,7 +17,7 @@ struct DistanceSortFunctor
 {
 	Vec3 origin;
 
-	bool operator()(SceneNode* a, SceneNode* b)
+	Bool operator()(SceneNode* a, SceneNode* b)
 	{
 		ANKI_ASSERT(a->getSpatial() != nullptr && b->getSpatial() != nullptr);
 
@@ -33,16 +33,21 @@ struct DistanceSortFunctor
 //==============================================================================
 struct MaterialSortFunctor
 {
-	// XXX
+	Bool operator()(SceneNode* a, SceneNode* b)
+	{
+		ANKI_ASSERT(a->getRenderable() != nullptr 
+			&& b->getRenderable() != nullptr);
+
+		return a->getRenderable()->getMaterial() 
+			< b->getRenderable()->getMaterial();
+	}
 };
 
 //==============================================================================
-struct TestJob: ThreadJob
+struct VisibilityTestJob: ThreadJob
 {
-	U count;
+	U nodesCount;
 	Scene::Types<SceneNode>::Container::iterator nodes;
-	VisibilityInfo::Renderables* renderables;
-	VisibilityInfo::Lights* lights;
 	std::mutex* renderablesMtx;
 	std::mutex* lightsMtx;
 	Frustumable* frustumable;
@@ -50,8 +55,8 @@ struct TestJob: ThreadJob
 	void operator()(U threadId, U threadsCount)
 	{
 		U64 start, end;
-		choseStartEnd(threadId, threadsCount, count, start, end);
-		const U TEMP_STORE_COUNT = 128;
+		choseStartEnd(threadId, threadsCount, nodesCount, start, end);
+		const U TEMP_STORE_COUNT = 512;
 		Array<SceneNode*, TEMP_STORE_COUNT> tmpRenderables;
 		Array<SceneNode*, TEMP_STORE_COUNT> tmpLights;
 		U renderablesIdx = 0;
@@ -100,20 +105,22 @@ struct TestJob: ThreadJob
 				{
 					tmpLights[lightsIdx++] = node;
 
-					/*if(l->getShadowEnabled() && fr)
+					if(l->getShadowEnabled() && fr)
 					{
-						testLight(*l, scene);
-					}*/
+						testLight(*l);
+					}
 				}
 			}
 		} // end for
 
+		VisibilityInfo& vinfo = frustumable->getVisibilityInfo();
+
 		// Write to containers
 		if(renderablesIdx > 0)
 		{
 			std::lock_guard<std::mutex> lock(*renderablesMtx);
 
-			renderables->insert(renderables->begin(),
+			vinfo.renderables.insert(vinfo.renderables.begin(),
 				&tmpRenderables[0],
 				&tmpRenderables[renderablesIdx]);
 		}
@@ -122,11 +129,52 @@ struct TestJob: ThreadJob
 		{
 			std::lock_guard<std::mutex> lock(*lightsMtx);
 
-			lights->insert(lights->begin(),
+			vinfo.lights.insert(vinfo.lights.begin(),
 				&tmpLights[0],
 				&tmpLights[lightsIdx]);
 		}
 	}
+
+	void testLight(Light& light)
+	{
+		Frustumable& ref = *light.getFrustumable();
+		ANKI_ASSERT(&ref != nullptr);
+
+		VisibilityInfo& vinfo = ref.getVisibilityInfo();
+		vinfo.renderables.clear();
+		vinfo.lights.clear();
+
+		for(auto it = nodes; it != nodes + nodesCount; it++)
+		{
+			SceneNode* node = *it;
+
+			Frustumable* fr = node->getFrustumable();
+			// Wont check the same
+			if(&ref == fr)
+			{
+				continue;
+			}
+
+			Spatial* sp = node->getSpatial();
+			if(!sp)
+			{
+				continue;
+			}
+
+			if(!ref.insideFrustum(*sp))
+			{
+				continue;
+			}
+
+			sp->enableFlag(Spatial::SF_VISIBLE);
+
+			Renderable* r = node->getRenderable();
+			if(r)
+			{
+				vinfo.renderables.push_back(node);
+			}
+		}
+	}
 };
 
 //==============================================================================
@@ -140,63 +188,32 @@ void VisibilityTester::test(Frustumable& ref, Scene& scene, Renderer& r)
 	vinfo.renderables.clear();
 	vinfo.lights.clear();
 
-	for(auto it = scene.getAllNodesBegin(); it != scene.getAllNodesEnd(); it++)
-	{
-		SceneNode* node = *it;
+	ThreadPool& threadPool = ThreadPoolSingleton::get();
+	VisibilityTestJob jobs[ThreadPool::MAX_THREADS];
 
-		Frustumable* fr = node->getFrustumable();
-		// Wont check the same
-		if(&ref == fr)
-		{
-			continue;
-		}
-
-		Spatial* sp = node->getSpatial();
-		if(!sp)
-		{
-			continue;
-		}
-
-		sp->disableFlag(Spatial::SF_VISIBLE);
-
-		if(!ref.insideFrustum(*sp))
-		{
-			continue;
-		}
+	std::mutex renderablesMtx;
+	std::mutex lightsMtx;
 
-		/*if(!r.doVisibilityTests(sp->getAabb()))
-		{
-			continue;
-		}*/
-
-		sp->enableFlag(Spatial::SF_VISIBLE);
-
-		Renderable* r = node->getRenderable();
-		if(r)
-		{
-			vinfo.renderables.push_back(node);
-		}
-		else
-		{
-			Light* l = node->getLight();
-			if(l)
-			{
-				vinfo.lights.push_back(node);
+	for(U i = 0; i < threadPool.getThreadsCount(); i++)
+	{
+		jobs[i].nodesCount = scene.getAllNodesCount();
+		jobs[i].nodes = scene.getAllNodesBegin();
+		jobs[i].renderablesMtx = &renderablesMtx;
+		jobs[i].lightsMtx = &lightsMtx;
+		jobs[i].frustumable = &ref;
 
-				if(l->getShadowEnabled() && fr)
-				{
-					testLight(*l, scene);
-				}
-			}
-		}
+		threadPool.assignNewJob(i, &jobs[i]);
 	}
 
+	threadPool.waitForAllJobsToFinish();
+
 	DistanceSortFunctor comp;
 	comp.origin =
 		ref.getSceneNode().getMovable()->getWorldTransform().getOrigin();
 	std::sort(vinfo.lights.begin(), vinfo.lights.end(), comp);
 
-	std::sort(vinfo.renderables.begin(), vinfo.renderables.end(), comp);
+	std::sort(vinfo.renderables.begin(), vinfo.renderables.end(), 
+		MaterialSortFunctor());
 }
 
 //==============================================================================

+ 28 - 0
src/util/StringList.cpp

@@ -1,8 +1,23 @@
 #include "anki/util/StringList.h"
 #include <sstream>
+#include <algorithm>
 
 namespace anki {
 
+//==============================================================================
+
+static bool compareStringsAsc(const StringList::String& a, 
+	const StringList::String& b)
+{
+	return a < b;
+}
+
+static bool compareStringsDesc(const StringList::String& a, 
+	const StringList::String& b)
+{
+	return a > b;
+}
+
 //==============================================================================
 StringList::String StringList::join(const Char* sep) const
 {
@@ -38,6 +53,19 @@ I StringList::getIndexOf(const Char* value) const
 	return (pos == size()) ? -1 : pos;
 }
 
+//==============================================================================
+void StringList::sortAll(const StringListSort method)
+{
+	if(method == SLS_ASCENDING)
+	{
+		std::sort(begin(), end(), compareStringsAsc);
+	}
+	else
+	{
+		std::sort(begin(), end(), compareStringsDesc);
+	}
+}
+
 //==============================================================================
 StringList StringList::splitString(const Char* s, Char seperator, Bool keep)
 {

+ 1 - 1
testapp/Main.cpp

@@ -403,7 +403,7 @@ void initSubsystems(int argc, char* argv[])
 	StdinListenerSingleton::get().start();
 
 	// Parallel jobs
-	ThreadPoolSingleton::get().init(4);
+	ThreadPoolSingleton::get().init(8);
 }
 
 //==============================================================================