Bladeren bron

IS parallelizing algorithms. Now lighting is wayyyy faster

Panagiotis Christopoulos Charitos 13 jaren geleden
bovenliggende
commit
f3788f8325
5 gewijzigde bestanden met toevoegingen van 135 en 91 verwijderingen
  1. 10 10
      .cproject
  2. 17 4
      include/anki/core/ThreadPool.h
  3. 4 1
      include/anki/renderer/Is.h
  4. 6 4
      src/core/ThreadPool.cpp
  5. 98 72
      src/renderer/Is.cpp

+ 10 - 10
.cproject

@@ -27,7 +27,7 @@
 									<listOptionValue builtIn="false" value="/usr/include"/>
 									<listOptionValue builtIn="false" value="/usr/include"/>
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/anki/anki}&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/anki/anki}&quot;"/>
 								</option>
 								</option>
-								<option id="gnu.cpp.compiler.option.preprocessor.def.703966797" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+								<option id="gnu.cpp.compiler.option.preprocessor.def.703966797" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 								</option>
 								</option>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1705857210" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1705857210" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -39,7 +39,7 @@
 									<listOptionValue builtIn="false" value="/usr/include"/>
 									<listOptionValue builtIn="false" value="/usr/include"/>
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/anki/anki}&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/anki/anki}&quot;"/>
 								</option>
 								</option>
-								<option id="gnu.c.compiler.option.preprocessor.def.symbols.1930194539" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.1930194539" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 								</option>
 								</option>
 								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1888715461" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
 								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1888715461" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
@@ -88,7 +88,7 @@
 							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1634217479" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
 							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1634217479" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
 								<option id="gnu.cpp.compiler.exe.release.option.optimization.level.467488783" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
 								<option id="gnu.cpp.compiler.exe.release.option.optimization.level.467488783" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
 								<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1206763877" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
 								<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1206763877" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
-								<option id="gnu.cpp.compiler.option.preprocessor.def.1535300050" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+								<option id="gnu.cpp.compiler.option.preprocessor.def.1535300050" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 								</option>
 								</option>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1897753799" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1897753799" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -96,7 +96,7 @@
 							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1453949923" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
 							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1453949923" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
 								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.204107120" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/>
 								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.204107120" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/>
 								<option id="gnu.c.compiler.exe.release.option.debugging.level.1402099681" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
 								<option id="gnu.c.compiler.exe.release.option.debugging.level.1402099681" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
-								<option id="gnu.c.compiler.option.preprocessor.def.symbols.1483582268" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.1483582268" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 									<listOptionValue builtIn="false" value="__GXX_EXPERIMENTAL_CXX0X__"/>
 								</option>
 								</option>
 								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.813305505" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
 								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.813305505" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
@@ -123,12 +123,16 @@
 	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 		<project id="anki.cdt.managedbuild.target.gnu.exe.1185865252" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
 		<project id="anki.cdt.managedbuild.target.gnu.exe.1185865252" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
 	</storageModule>
 	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="1">
+		<resource resourceType="PROJECT" workspacePath="/anki"/>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 	<storageModule moduleId="scannerConfiguration">
 	<storageModule moduleId="scannerConfiguration">
 		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
 		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.571635259;cdt.managedbuild.config.gnu.exe.release.571635259.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1634217479;cdt.managedbuild.tool.gnu.cpp.compiler.input.1897753799">
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1191103617;cdt.managedbuild.config.gnu.exe.debug.1191103617.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.733325444;cdt.managedbuild.tool.gnu.cpp.compiler.input.1705857210">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 		</scannerConfigBuildInfo>
 		</scannerConfigBuildInfo>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1191103617;cdt.managedbuild.config.gnu.exe.debug.1191103617.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.733325444;cdt.managedbuild.tool.gnu.cpp.compiler.input.1705857210">
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.571635259;cdt.managedbuild.config.gnu.exe.release.571635259.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1634217479;cdt.managedbuild.tool.gnu.cpp.compiler.input.1897753799">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 		</scannerConfigBuildInfo>
 		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1191103617;cdt.managedbuild.config.gnu.exe.debug.1191103617.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.509716139;cdt.managedbuild.tool.gnu.c.compiler.input.1888715461">
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1191103617;cdt.managedbuild.config.gnu.exe.debug.1191103617.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.509716139;cdt.managedbuild.tool.gnu.c.compiler.input.1888715461">
@@ -138,8 +142,4 @@
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
 		</scannerConfigBuildInfo>
 	</storageModule>
 	</storageModule>
-	<storageModule moduleId="refreshScope" versionNumber="1">
-		<resource resourceType="PROJECT" workspacePath="/anki"/>
-	</storageModule>
-	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 </cproject>
 </cproject>

+ 17 - 4
include/anki/core/ThreadPool.h

@@ -18,7 +18,17 @@ struct ThreadJob
 	virtual ~ThreadJob()
 	virtual ~ThreadJob()
 	{}
 	{}
 
 
-	virtual void operator()() = 0;
+	virtual void operator()(U threadId, U threadsCount) = 0;
+
+	/// Chose a starting and end index
+	void choseStartEnd(U threadId, U threadsCount, U64 elementsCount,
+		U64& start, U64& end)
+	{
+		start = threadId * (elementsCount / threadsCount);
+		end = (threadId == threadsCount - 1)
+			? elementsCount
+			: start + elementsCount / threadsCount;
+	}
 };
 };
 
 
 /// A dummy job
 /// A dummy job
@@ -33,7 +43,7 @@ class ThreadWorker
 {
 {
 public:
 public:
 	/// Constructor
 	/// Constructor
-	ThreadWorker(U32 id, Barrier* barrier);
+	ThreadWorker(U32 id, Barrier* barrier, ThreadPool* threadPool);
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
@@ -53,6 +63,7 @@ private:
 	std::condition_variable condVar; ///< To wake up the thread
 	std::condition_variable condVar; ///< To wake up the thread
 	Barrier* barrier = nullptr; ///< For synchronization
 	Barrier* barrier = nullptr; ///< For synchronization
 	ThreadJob* job = nullptr; ///< Its NULL if there are no pending job
 	ThreadJob* job = nullptr; ///< Its NULL if there are no pending job
+	ThreadPool* threadPool;
 
 
 	/// Start thread
 	/// Start thread
 	void start()
 	void start()
@@ -69,6 +80,8 @@ private:
 class ThreadPool
 class ThreadPool
 {
 {
 public:
 public:
+	static constexpr U MAX_THREADS = 32; ///< An absolute limit
+
 	/// Default constructor
 	/// Default constructor
 	ThreadPool()
 	ThreadPool()
 	{}
 	{}
@@ -83,7 +96,7 @@ public:
 	void init(U threadsNum);
 	void init(U threadsNum);
 
 
 	/// Assign a job to a working thread
 	/// Assign a job to a working thread
-	void assignNewJob(uint jobId, ThreadJob* job)
+	void assignNewJob(U jobId, ThreadJob* job)
 	{
 	{
 		jobs[jobId]->assignNewJob(job);
 		jobs[jobId]->assignNewJob(job);
 	}
 	}
@@ -94,7 +107,7 @@ public:
 		barrier->wait();
 		barrier->wait();
 	}
 	}
 
 
-	uint getThreadsNum() const
+	uint getThreadsCount() const
 	{
 	{
 		return jobs.size();
 		return jobs.size();
 	}
 	}

+ 4 - 1
include/anki/renderer/Is.h

@@ -21,6 +21,8 @@ class SpotLight;
 /// Illumination stage
 /// Illumination stage
 class Is: private RenderingPass
 class Is: private RenderingPass
 {
 {
+	friend class WriteTilesUboJob;
+
 public:
 public:
 	// Config. These values affect the size of the uniform blocks and keep in
 	// Config. These values affect the size of the uniform blocks and keep in
 	// mind that there are size limitations in uniform blocks.
 	// mind that there are size limitations in uniform blocks.
@@ -118,7 +120,8 @@ public: // XXX
 	void updateTiles();
 	void updateTiles();
 
 
 	/// See if the light is inside the tile
 	/// See if the light is inside the tile
-	Bool cullLight(const PointLight& light, const Tile& tile);
+	static Bool cullLight(const PointLight& light, const Tile& tile, 
+		const Mat4& viewMatrix);
 	Bool cullLight(const SpotLight& light, const Tile& tile);
 	Bool cullLight(const SpotLight& light, const Tile& tile);
 
 
 	/// Do the light culling
 	/// Do the light culling

+ 6 - 4
src/core/ThreadPool.cpp

@@ -7,8 +7,8 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-ThreadWorker::ThreadWorker(U32 id_, Barrier* barrier_)
-	: id(id_), barrier(barrier_)
+ThreadWorker::ThreadWorker(U32 id_, Barrier* barrier_, ThreadPool* threadPool_)
+	: id(id_), barrier(barrier_), threadPool(threadPool_)
 {
 {
 	start();
 	start();
 }
 }
@@ -38,7 +38,7 @@ void ThreadWorker::workingFunc()
 		}
 		}
 
 
 		// Exec
 		// Exec
-		(*job)();
+		(*job)(id, threadPool->getThreadsCount());
 
 
 		// Nullify
 		// Nullify
 		{
 		{
@@ -57,11 +57,13 @@ void ThreadWorker::workingFunc()
 //==============================================================================
 //==============================================================================
 void ThreadPool::init(U threadsNum)
 void ThreadPool::init(U threadsNum)
 {
 {
+	ANKI_ASSERT(threadsNum <= MAX_THREADS);
+
 	barrier.reset(new Barrier(threadsNum + 1));
 	barrier.reset(new Barrier(threadsNum + 1));
 
 
 	for(U i = 0; i < threadsNum; i++)
 	for(U i = 0; i < threadsNum; i++)
 	{
 	{
-		jobs.push_back(new ThreadWorker(i, barrier.get()));
+		jobs.push_back(new ThreadWorker(i, barrier.get(), this));
 	}
 	}
 }
 }
 
 

+ 98 - 72
src/renderer/Is.cpp

@@ -46,7 +46,8 @@ struct ShaderTile
 
 
 struct ShaderTiles
 struct ShaderTiles
 {
 {
-	Array<Array<ShaderTile, Is::TILES_X_COUNT>, Is::TILES_Y_COUNT> tiles;
+	//Array<Array<ShaderTile, Is::TILES_X_COUNT>, Is::TILES_Y_COUNT> tiles;
+	Array<ShaderTile, Is::TILES_X_COUNT * Is::TILES_Y_COUNT> tiles;
 };
 };
 
 
 struct ShaderCommonUniforms
 struct ShaderCommonUniforms
@@ -61,9 +62,79 @@ struct ShaderCommonUniforms
 /// XXX
 /// XXX
 struct UbosUpdateJob: ThreadJob
 struct UbosUpdateJob: ThreadJob
 {
 {
-	ShaderPointLights* pointLights;
-	PointLight* visibleLights;
+	ShaderPointLights* lightsMappedBuff;
+	PointLight** visibleLights;
 	U32 visibleLightsCount;
 	U32 visibleLightsCount;
+	Camera* cam;
+
+	void operator()(U threadId, U threadsCount)
+	{
+		U64 start, end;
+		choseStartEnd(threadId, threadsCount, visibleLightsCount, start, end);
+
+		for(U64 i = start; i < end; i++)
+		{
+			ShaderPointLight& pl = lightsMappedBuff->lights[i];
+			const PointLight& plight = *visibleLights[i];
+
+			Vec3 pos = plight.getWorldTransform().getOrigin().getTransformed(
+				cam->getViewMatrix());
+
+
+			pl.posAndRadius = Vec4(pos, plight.getRadius());
+			pl.diffuseColor = plight.getDiffuseColor();
+			pl.specularColor = plight.getSpecularColor();
+		}
+	}
+};
+
+/// XXX
+struct WriteTilesUboJob: ThreadJob
+{
+	PointLight** visibleLights;
+	U32 visibleLightsCount;
+	Is::Tile* tiles;
+	U tilesCount;
+	ShaderTiles* stiles;
+	Mat4 viewMatrix;
+
+	void operator()(U threadId, U threadsCount)
+	{
+		U64 start, end;
+		choseStartEnd(threadId, threadsCount, tilesCount, start, end);
+
+		for(U64 i = start; i < end; i++)
+		{
+			Is::Tile& tile = tiles[i];
+			Array<U32, Is::MAX_LIGHTS_PER_TILE> lightIndices;
+			U lightsInTileCount = 0;
+
+			for(U j = 0; j < visibleLightsCount; j++)
+			{
+				const PointLight& plight = *visibleLights[j];
+
+				if(Is::cullLight(plight, tile, viewMatrix))
+				{
+					// Use % to avoid overflows
+					lightIndices[lightsInTileCount 
+						% Is::MAX_LIGHTS_PER_TILE] = j;
+					++lightsInTileCount;
+				}
+			}
+#if 0
+			if(lightsInTileCount > MAX_LIGHTS_PER_TILE)
+			{
+				ANKI_LOGW("Too many lights per tile: " << lightsInTileCount);
+			}
+#endif
+			stiles->tiles[i].lightsCount = lightsInTileCount;
+
+			memcpy(
+				&(stiles->tiles[i].lightIndices[0]),
+				&lightIndices[0],
+				sizeof(lightIndices));
+		}
+	}
 };
 };
 
 
 //==============================================================================
 //==============================================================================
@@ -208,15 +279,11 @@ void Is::initInternal(const RendererInitializer& initializer)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Bool Is::cullLight(const PointLight& plight, const Tile& tile)
+Bool Is::cullLight(const PointLight& plight, const Tile& tile, 
+	const Mat4& viewMatrix)
 {
 {
-	Camera& cam = r->getScene().getActiveCamera();
 	Sphere sphere = plight.getSphere();
 	Sphere sphere = plight.getSphere();
-
-	//return cam.getFrustumable()->getFrustum().insideFrustum(sphere);
-
-#if 1
-	sphere.transform(Transform(cam.getViewMatrix()));
+	sphere.transform(Transform(viewMatrix));
 
 
 	for(const Plane& plane : tile.planes)
 	for(const Plane& plane : tile.planes)
 	{
 	{
@@ -227,7 +294,6 @@ Bool Is::cullLight(const PointLight& plight, const Tile& tile)
 	}
 	}
 
 
 	return true;
 	return true;
-#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -371,6 +437,8 @@ void Is::pointLightsPass()
 	Array<PointLight*, MAX_LIGHTS> visibleLights;
 	Array<PointLight*, MAX_LIGHTS> visibleLights;
 	U visibleLightsCount = 0;
 	U visibleLightsCount = 0;
 
 
+	ThreadPool& threadPool = ThreadPoolSingleton::get();
+
 	//
 	//
 	// Write the lightsUbo
 	// Write the lightsUbo
 	//
 	//
@@ -399,84 +467,42 @@ void Is::pointLightsPass()
 		sizeof(ShaderPointLight) * visibleLightsCount,
 		sizeof(ShaderPointLight) * visibleLightsCount,
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 
 
-	// Write the buff
-	for(U i = 0; i < visibleLightsCount; i++)
+	UbosUpdateJob jobs[ThreadPool::MAX_THREADS];
+	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
 	{
-		ShaderPointLight& pl = lightsMappedBuff->lights[i];
-		const PointLight& plight = *visibleLights[i];
-
-		Vec3 pos = plight.getWorldTransform().getOrigin().getTransformed(
-			cam.getViewMatrix());
-
+		jobs[i].cam = &cam;
+		jobs[i].lightsMappedBuff = lightsMappedBuff;
+		jobs[i].visibleLights = &visibleLights[0];
+		jobs[i].visibleLightsCount = visibleLightsCount;
 
 
-		pl.posAndRadius = Vec4(pos, plight.getRadius());
-		pl.diffuseColor = plight.getDiffuseColor();
-		pl.specularColor = plight.getSpecularColor();
+		threadPool.assignNewJob(i, &jobs[i]);
 	}
 	}
 
 
 	// Done
 	// Done
+	threadPool.waitForAllJobsToFinish();
 	lightsUbo.unmap();
 	lightsUbo.unmap();
 
 
-#if 1
 	//
 	//
 	// Update the tiles
 	// Update the tiles
 	//
 	//
 
 
-	// For all tiles write their indices 
-	// OPT Parallelize that!!!!!!!!!!!!
-	for(U j = 0; j < TILES_Y_COUNT; j++)
-	{
-		for(U i = 0; i < TILES_X_COUNT; i++)
-		{
-			Tile& tile = tiles[j][i];
-
-			U lightsInTileCount = 0;
-
-			for(U i = 0; i < visibleLightsCount; i++)
-			{
-				const PointLight& plight = *visibleLights[i];
-
-				if(cullLight(plight, tile))
-				{
-					// Use % to avoid overflows
-					tile.lightIndices[lightsInTileCount 
-						% MAX_LIGHTS_PER_TILE] = i;
-					++lightsInTileCount;
-				}
-			}
-
-			/*if(lightsInTileCount > MAX_LIGHTS_PER_TILE)
-			{
-				//throw ANKI_EXCEPTION("Too many lights per tile");
-				ANKI_LOGW("Too many lights per tile: " << lightsInTileCount);
-			}*/
-
-			tile.lightsCount = lightsInTileCount;
-		}
-	}
-#endif
-
-	//
-	// Write the tilesUbo
-	//
 	ShaderTiles* stiles = (ShaderTiles*)tilesUbo.map(
 	ShaderTiles* stiles = (ShaderTiles*)tilesUbo.map(
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 
 
-	for(U j = 0; j < TILES_Y_COUNT; j++)
+	WriteTilesUboJob tjobs[ThreadPool::MAX_THREADS];
+	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
 	{
-		for(U i = 0; i < TILES_X_COUNT; i++)
-		{
-			const Tile& tile = tiles[j][i];
-
-			stiles->tiles[j][i].lightsCount = tile.lightsCount;
-
-			memcpy(
-				&(stiles->tiles[j][i].lightIndices[0]),
-				&tile.lightIndices[0],
-				sizeof(U32) * MAX_LIGHTS_PER_TILE);
-		}
+		tjobs[i].visibleLights = &visibleLights[0];
+		tjobs[i].visibleLightsCount = visibleLightsCount;
+		tjobs[i].tiles = &tiles[0][0];
+		tjobs[i].tilesCount = TILES_X_COUNT * TILES_Y_COUNT;
+		tjobs[i].stiles = stiles;
+		tjobs[i].viewMatrix = cam.getViewMatrix();
+
+		threadPool.assignNewJob(i, &tjobs[i]);
 	}
 	}
 
 
+	threadPool.waitForAllJobsToFinish();
 	tilesUbo.unmap();
 	tilesUbo.unmap();
 
 
 	//
 	//