Browse Source

Removing exceptions

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
00b02c714e
52 changed files with 1555 additions and 816 deletions
  1. 2 2
      include/anki/renderer/Bs.h
  2. 3 2
      include/anki/renderer/Dbg.h
  3. 13 5
      include/anki/renderer/DebugDrawer.h
  4. 2 2
      include/anki/renderer/Drawer.h
  5. 2 2
      include/anki/renderer/Ez.h
  6. 5 5
      include/anki/renderer/Hdr.h
  7. 5 5
      include/anki/renderer/Is.h
  8. 3 3
      include/anki/renderer/Lf.h
  9. 7 9
      include/anki/renderer/MainRenderer.h
  10. 4 3
      include/anki/renderer/Ms.h
  11. 3 3
      include/anki/renderer/Pps.h
  12. 15 12
      include/anki/renderer/Renderer.h
  13. 2 2
      include/anki/renderer/RenderingPass.h
  14. 12 7
      include/anki/renderer/Sm.h
  15. 5 4
      include/anki/renderer/Ssao.h
  16. 2 2
      include/anki/renderer/Sslr.h
  17. 4 5
      include/anki/renderer/Tiler.h
  18. 41 30
      include/anki/resource/AsyncLoader.h
  19. 14 12
      include/anki/scene/ParticleEmitter.h
  20. 23 17
      include/anki/scene/SceneGraph.h
  21. 13 1
      include/anki/util/DArray.h
  22. 2 2
      include/anki/util/StringList.h
  23. 6 7
      include/anki/util/StringList.inl.h
  24. 15 7
      src/misc/Xml.cpp
  25. 22 13
      src/renderer/Bs.cpp
  26. 62 27
      src/renderer/Dbg.cpp
  27. 73 27
      src/renderer/DebugDrawer.cpp
  28. 34 10
      src/renderer/Drawer.cpp
  29. 16 8
      src/renderer/Ez.cpp
  30. 80 37
      src/renderer/Hdr.cpp
  31. 81 42
      src/renderer/Is.cpp
  32. 95 36
      src/renderer/Lf.cpp
  33. 41 24
      src/renderer/MainRenderer.cpp
  34. 78 47
      src/renderer/Ms.cpp
  35. 49 27
      src/renderer/Pps.cpp
  36. 107 49
      src/renderer/Renderer.cpp
  37. 27 11
      src/renderer/RenderingPass.cpp
  38. 42 22
      src/renderer/Sm.cpp
  39. 76 39
      src/renderer/Ssao.cpp
  40. 32 15
      src/renderer/Sslr.cpp
  41. 46 26
      src/renderer/Tiler.cpp
  42. 26 14
      src/resource/AsyncLoader.cpp
  43. 1 1
      src/resource/MaterialProgramCreator.cpp
  44. 1 2
      src/resource/ProgramPrePreprocessor.cpp
  45. 4 2
      src/resource/ResourceManager.cpp
  46. 16 6
      src/scene/Light.cpp
  47. 5 2
      src/scene/MoveComponent.cpp
  48. 212 108
      src/scene/ParticleEmitter.cpp
  49. 104 59
      src/scene/SceneGraph.cpp
  50. 13 12
      src/script/LuaBinder.cpp
  51. 8 0
      src/script/Util.cpp
  52. 1 1
      src/util/Memory.cpp

+ 2 - 2
include/anki/renderer/Bs.h

@@ -25,8 +25,8 @@ private:
 
 
 	~Bs();
 	~Bs();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdb);
 };
 };
 
 
 /// @}
 /// @}

+ 3 - 2
include/anki/renderer/Dbg.h

@@ -70,8 +70,9 @@ private:
 	
 	
 	~Dbg();
 	~Dbg();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& jobs);
 };
 };
 
 
 /// @}
 /// @}

+ 13 - 5
include/anki/renderer/DebugDrawer.h

@@ -26,9 +26,11 @@ class Renderer;
 class DebugDrawer
 class DebugDrawer
 {
 {
 public:
 public:
-	DebugDrawer(Renderer* r);
+	DebugDrawer();
 	~DebugDrawer();
 	~DebugDrawer();
 
 
+	ANKI_USE_RESULT Error create(Renderer* r);
+
 	void drawGrid();
 	void drawGrid();
 	void drawSphere(F32 radius, I complexity = 4);
 	void drawSphere(F32 radius, I complexity = 4);
 	void drawCube(F32 size = 1.0);
 	void drawCube(F32 size = 1.0);
@@ -47,24 +49,30 @@ public:
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
 	/// @{
 	/// @{
 	void begin(GLenum primitive); ///< Initiates the draw
 	void begin(GLenum primitive); ///< Initiates the draw
+
 	void end(); ///< Draws
 	void end(); ///< Draws
+
 	void pushBackVertex(const Vec3& pos); ///< Something like glVertex
 	void pushBackVertex(const Vec3& pos); ///< Something like glVertex
+
 	/// Something like glColor
 	/// Something like glColor
 	void setColor(const Vec3& col)
 	void setColor(const Vec3& col)
 	{
 	{
 		m_crntCol = col;
 		m_crntCol = col;
 	}
 	}
+
 	/// Something like glColor
 	/// Something like glColor
 	void setColor(const Vec4& col)
 	void setColor(const Vec4& col)
 	{
 	{
 		m_crntCol = col.xyz();
 		m_crntCol = col.xyz();
 	}
 	}
+
 	void setModelMatrix(const Mat4& m);
 	void setModelMatrix(const Mat4& m);
+
 	void setViewProjectionMatrix(const Mat4& m);
 	void setViewProjectionMatrix(const Mat4& m);
 	/// @}
 	/// @}
 
 
 	/// This is the function that actualy draws
 	/// This is the function that actualy draws
-	void flush();
+	ANKI_USE_RESULT Error flush();
 
 
 private:
 private:
 	class Vertex
 	class Vertex
@@ -88,17 +96,17 @@ private:
 	Vec3 m_crntCol;
 	Vec3 m_crntCol;
 	GLenum m_primitive;
 	GLenum m_primitive;
 
 
+	GlBufferHandle m_vertBuff;
+
 	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientLineVerts;
 	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientLineVerts;
 	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientTriVerts;
 	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientTriVerts;
 
 
-	GlBufferHandle m_vertBuff;
-
 	/// This is a container of some precalculated spheres. Its a map that
 	/// This is a container of some precalculated spheres. Its a map that
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// pairs)
 	/// pairs)
 	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
 	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
 
 
-	void flushInternal(GLenum primitive);
+	ANKI_USE_RESULT Error flushInternal(GLenum primitive);
 };
 };
 
 
 /// Contains methods to render the collision shapes
 /// Contains methods to render the collision shapes

+ 2 - 2
include/anki/renderer/Drawer.h

@@ -36,12 +36,12 @@ public:
 	static const U32 MAX_UNIFORM_BUFFER_SIZE = 1024 * 1024 * 1;
 	static const U32 MAX_UNIFORM_BUFFER_SIZE = 1024 * 1024 * 1;
 
 
 	/// The one and only constructor
 	/// The one and only constructor
-	RenderableDrawer(Renderer* r);
+	ANKI_USE_RESULT Error create(Renderer* r);
 
 
 	void prepareDraw(
 	void prepareDraw(
 		RenderingStage stage, Pass pass, GlCommandBufferHandle& cmdBuff);
 		RenderingStage stage, Pass pass, GlCommandBufferHandle& cmdBuff);
 
 
-	void render(
+	ANKI_USE_RESULT Error render(
 		SceneNode& frsn,
 		SceneNode& frsn,
 		VisibleNode& visible);
 		VisibleNode& visible);
 
 

+ 2 - 2
include/anki/renderer/Ez.h

@@ -26,8 +26,8 @@ private:
 	:	RenderingPass(r)
 	:	RenderingPass(r)
 	{}
 	{}
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
 };
 };
 
 
 /// @}
 /// @}

+ 5 - 5
include/anki/renderer/Hdr.h

@@ -97,13 +97,13 @@ private:
 
 
 	~Hdr();
 	~Hdr();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& jobs);
 
 
-	void initFb(GlFramebufferHandle& fb, GlTextureHandle& rt);
-	void initInternal(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error initFb(GlFramebufferHandle& fb, GlTextureHandle& rt);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 
 
-	void updateDefaultBlock(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error updateDefaultBlock(GlCommandBufferHandle& jobs);
 };
 };
 
 
 /// @}
 /// @}

+ 5 - 5
include/anki/renderer/Is.h

@@ -113,14 +113,14 @@ private:
 	Is(Renderer* r);
 	Is(Renderer* r);
 	~Is();
 	~Is();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
 
 
 	/// Called by init
 	/// Called by init
-	void initInternal(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 
 
 	/// Do the actual pass
 	/// Do the actual pass
-	void lightPass(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error lightPass(GlCommandBufferHandle& cmdBuff);
 
 
 	/// Prepare GL for rendering
 	/// Prepare GL for rendering
 	void setState(GlCommandBufferHandle& cmdBuff);
 	void setState(GlCommandBufferHandle& cmdBuff);
@@ -131,7 +131,7 @@ private:
 	/// Calculate the size of the tile
 	/// Calculate the size of the tile
 	PtrSize calcTileSize() const;
 	PtrSize calcTileSize() const;
 
 
-	void updateCommonBlock(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error updateCommonBlock(GlCommandBufferHandle& cmdBuff);
 };
 };
 
 
 /// @}
 /// @}

+ 3 - 3
include/anki/renderer/Lf.h

@@ -63,10 +63,10 @@ private:
 
 
 	~Lf();
 	~Lf();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& jobs);
 	
 	
-	void initInternal(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 };
 };
 
 
 /// @}
 /// @}

+ 7 - 9
include/anki/renderer/MainRenderer.h

@@ -17,16 +17,18 @@ namespace anki {
 class MainRenderer: public Renderer
 class MainRenderer: public Renderer
 {
 {
 public:
 public:
-	MainRenderer(
+	MainRenderer();
+
+	~MainRenderer();
+
+	ANKI_USE_RESULT Error init(
 		Threadpool* threadpool, 
 		Threadpool* threadpool, 
 		ResourceManager* resources,
 		ResourceManager* resources,
 		GlDevice* gl,
 		GlDevice* gl,
 		HeapAllocator<U8>& alloc,
 		HeapAllocator<U8>& alloc,
 		const ConfigSet& config);
 		const ConfigSet& config);
 
 
-	~MainRenderer();
-
-	void render(SceneGraph& scene);
+	ANKI_USE_RESULT Error render(SceneGraph& scene);
 
 
 	/// Save the color buffer to a tga (lossless & uncompressed & slow)
 	/// Save the color buffer to a tga (lossless & uncompressed & slow)
 	/// or jpeg (lossy & compressed fast)
 	/// or jpeg (lossy & compressed fast)
@@ -40,12 +42,8 @@ private:
 	/// Optimize job chain
 	/// Optimize job chain
 	Array<GlCommandBufferInitHints, JOB_CHAINS_COUNT> m_jobsInitHints; 
 	Array<GlCommandBufferInitHints, JOB_CHAINS_COUNT> m_jobsInitHints; 
 
 
-	/// The same as Renderer::init but with additional initialization.
-	/// @see Renderer::init
-	void init(const ConfigSet& initializer);
-
 	void takeScreenshotTga(const char* filename);
 	void takeScreenshotTga(const char* filename);
-	void initGl();
+	ANKI_USE_RESULT Error initGl();
 };
 };
 
 
 /// @}
 /// @}

+ 4 - 3
include/anki/renderer/Ms.h

@@ -77,11 +77,12 @@ private:
 
 
 	~Ms();
 	~Ms();
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& jobs);
 
 
 	/// Create a G buffer FBO
 	/// Create a G buffer FBO
-	void createRt(U32 index, U32 samples);
+	ANKI_USE_RESULT Error createRt(U32 index, U32 samples);
 };
 };
 
 
 /// @}
 /// @}

+ 3 - 3
include/anki/renderer/Pps.h

@@ -102,10 +102,10 @@ private:
 	Pps(Renderer* r);
 	Pps(Renderer* r);
 	~Pps();
 	~Pps();
 
 
-	void init(const ConfigSet& config);
-	void run(GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error init(const ConfigSet& config);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& jobs);
 
 
-	void initInternal(const ConfigSet& config);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& config);
 };
 };
 
 
 /// @}
 /// @}

+ 15 - 12
include/anki/renderer/Renderer.h

@@ -39,12 +39,7 @@ public:
 	/// GL with a huge job chain
 	/// GL with a huge job chain
 	static const U32 JOB_CHAINS_COUNT = 2;
 	static const U32 JOB_CHAINS_COUNT = 2;
 		
 		
-	Renderer(
-		Threadpool* threadpool, 
-		ResourceManager* resources,
-		GlDevice* gl,
-		HeapAllocator<U8>& alloc,
-		const ConfigSet& config);
+	Renderer();
 
 
 	~Renderer();
 	~Renderer();
 
 
@@ -188,7 +183,7 @@ public:
 	}
 	}
 
 
 	/// This function does all the rendering stages and produces a final FAI
 	/// This function does all the rendering stages and produces a final FAI
-	void render(SceneGraph& scene, 
+	ANKI_USE_RESULT Error render(SceneGraph& scene, 
 		Array<GlCommandBufferHandle, JOB_CHAINS_COUNT>& cmdBuff);
 		Array<GlCommandBufferHandle, JOB_CHAINS_COUNT>& cmdBuff);
 
 
 	/// My version of gluUnproject
 	/// My version of gluUnproject
@@ -214,17 +209,23 @@ public:
 	}
 	}
 
 
 	/// Create a framebuffer attachment texture
 	/// Create a framebuffer attachment texture
-	void createRenderTarget(U32 w, U32 h, GLenum internalFormat, 
-		GLenum format, GLenum type, U32 samples, GlTextureHandle& rt);
+	ANKI_USE_RESULT Error createRenderTarget(U32 w, U32 h, 
+		GLenum internalFormat, GLenum format, GLenum type, U32 samples, 
+		GlTextureHandle& rt);
 
 
 	/// Create a pipeline object that has as a vertex shader the m_drawQuadVert
 	/// Create a pipeline object that has as a vertex shader the m_drawQuadVert
 	/// and the given fragment progam
 	/// and the given fragment progam
-	GlProgramPipelineHandle createDrawQuadProgramPipeline(
-		GlProgramHandle frag);
+	ANKI_USE_RESULT Error createDrawQuadProgramPipeline(
+		GlProgramHandle frag, GlProgramPipelineHandle& ppline);
 
 
 	/// Init the renderer given an initialization class
 	/// Init the renderer given an initialization class
 	/// @param initializer The initializer class
 	/// @param initializer The initializer class
-	void init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error init(
+		Threadpool* threadpool, 
+		ResourceManager* resources,
+		GlDevice* gl,
+		HeapAllocator<U8>& alloc,
+		const ConfigSet& config);
 
 
 	/// @privatesection
 	/// @privatesection
 	/// @{
 	/// @{
@@ -308,6 +309,8 @@ private:
 	String m_shadersPrependedSource; ///< String to append in user shaders
 	String m_shadersPrependedSource; ///< String to append in user shaders
 
 
 	void computeProjectionParams(const Mat4& projMat);
 	void computeProjectionParams(const Mat4& projMat);
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 };
 };
 
 
 /// @}
 /// @}

+ 2 - 2
include/anki/renderer/RenderingPass.h

@@ -80,10 +80,10 @@ protected:
 
 
 	Array<Direction, 2> m_dirs;
 	Array<Direction, 2> m_dirs;
 
 
-	void initBlurring(Renderer& r, U width, U height, U samples, 
+	ANKI_USE_RESULT Error initBlurring(Renderer& r, U width, U height, U samples, 
 		F32 blurringDistance);
 		F32 blurringDistance);
 
 
-	void runBlurring(Renderer& r, GlCommandBufferHandle& jobs);
+	ANKI_USE_RESULT Error runBlurring(Renderer& r, GlCommandBufferHandle& jobs);
 };
 };
 
 
 /// @}
 /// @}

+ 12 - 7
include/anki/renderer/Sm.h

@@ -52,7 +52,7 @@ private:
 		U32 m_timestamp = 0; ///< Timestamp of last render or light change
 		U32 m_timestamp = 0; ///< Timestamp of last render or light change
 	};
 	};
 
 
-	Vector<Shadowmap> m_sms;
+	DArray<Shadowmap> m_sms;
 
 
 	/// If false then disable SM at all
 	/// If false then disable SM at all
 	Bool8 m_enabled; 
 	Bool8 m_enabled; 
@@ -67,18 +67,22 @@ private:
 	U32 m_resolution;
 	U32 m_resolution;
 
 
 	Sm(Renderer* r)
 	Sm(Renderer* r)
-	:	RenderingPass(r),
-		m_sms(getAllocator())
+	:	RenderingPass(r)
 	{}
 	{}
 
 
-	void init(const ConfigSet& initializer);
-	void run(Light* shadowCasters[], U32 shadowCastersCount, 
+	~Sm()
+	{
+		m_sms.destroy(getAllocator());
+	}
+
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(Light* shadowCasters[], U32 shadowCastersCount, 
 		GlCommandBufferHandle& cmdBuff);
 		GlCommandBufferHandle& cmdBuff);
 
 
 	/// Get max shadow casters
 	/// Get max shadow casters
 	U32 getMaxLightsCount()
 	U32 getMaxLightsCount()
 	{
 	{
-		return m_sms.size();
+		return m_sms.getSize();
 	}
 	}
 
 
 	void prepareDraw(GlCommandBufferHandle& cmdBuff);
 	void prepareDraw(GlCommandBufferHandle& cmdBuff);
@@ -87,7 +91,8 @@ private:
 	/// Find the best shadowmap for that light
 	/// Find the best shadowmap for that light
 	Shadowmap& bestCandidate(Light& light);
 	Shadowmap& bestCandidate(Light& light);
 
 
-	Shadowmap* doLight(Light& light, GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error doLight(
+		Light& light, GlCommandBufferHandle& cmdBuff, Shadowmap*& sm);
 };
 };
 
 
 /// @}
 /// @}

+ 5 - 4
include/anki/renderer/Ssao.h

@@ -49,16 +49,17 @@ private:
 	:	RenderingPass(r)
 	:	RenderingPass(r)
 	{}
 	{}
 
 
-	void init(const ConfigSet& initializer);
-	void run(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
 
 
 	GlTextureHandle& getRt()
 	GlTextureHandle& getRt()
 	{
 	{
 		return m_vblurRt;
 		return m_vblurRt;
 	}
 	}
 
 
-	void createFb(GlFramebufferHandle& fb, GlTextureHandle& rt);
-	void initInternal(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error createFb(
+		GlFramebufferHandle& fb, GlTextureHandle& rt);
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 };
 };
 
 
 /// @}
 /// @}

+ 2 - 2
include/anki/renderer/Sslr.h

@@ -46,8 +46,8 @@ private:
 	:	BlurringRenderingPass(r)
 	:	BlurringRenderingPass(r)
 	{}
 	{}
 
 
-	void init(const ConfigSet& config);
-	void run(GlCommandBufferHandle& cmdBuff);
+	ANKI_USE_RESULT Error init(const ConfigSet& config);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
 };
 };
 
 
 /// @}
 /// @}

+ 4 - 5
include/anki/renderer/Tiler.h

@@ -23,8 +23,7 @@ class Frustumable;
 /// Tiler used for visibility tests
 /// Tiler used for visibility tests
 class Tiler: public RenderingPass
 class Tiler: public RenderingPass
 {
 {
-	friend struct UpdateTilesPlanesPerspectiveCameraJob;
-	friend struct UpdatePlanesPerspectiveCameraJob;
+	friend struct UpdatePlanesPerspectiveCameraTask;
 
 
 public:
 public:
 	using Bitset = std::bitset<
 	using Bitset = std::bitset<
@@ -33,7 +32,7 @@ public:
 	Tiler(Renderer* r);
 	Tiler(Renderer* r);
 	~Tiler();
 	~Tiler();
 
 
-	void init();
+	Error init();
 
 
 	/// Issue the GPU job
 	/// Issue the GPU job
 	void runMinMax(const GlTextureHandle& depthMap);
 	void runMinMax(const GlTextureHandle& depthMap);
@@ -53,7 +52,7 @@ public:
 
 
 private:
 private:
 	/// Tile planes
 	/// Tile planes
-	Vector<Plane> m_allPlanes;
+	DArray<Plane> m_allPlanes;
 	Plane* m_planesY = nullptr;
 	Plane* m_planesY = nullptr;
 	Plane* m_planesX = nullptr;
 	Plane* m_planesX = nullptr;
 	Plane* m_planesYW = nullptr;
 	Plane* m_planesYW = nullptr;
@@ -81,7 +80,7 @@ private:
 	/// Timestamp for the same reason as prevCam
 	/// Timestamp for the same reason as prevCam
 	Timestamp m_planes4UpdateTimestamp = getGlobTimestamp();
 	Timestamp m_planes4UpdateTimestamp = getGlobTimestamp();
 
 
-	void initInternal();
+	ANKI_USE_RESULT Error initInternal();
 
 
 	void testRange(const CollisionShape& cs, Bool nearPlane,
 	void testRange(const CollisionShape& cs, Bool nearPlane,
 		U iFrom, U iTo, U jFrom, U jTo, Bitset& bitset) const;
 		U iFrom, U iTo, U jFrom, U jTo, Bitset& bitset) const;

+ 41 - 30
include/anki/resource/AsyncLoader.h

@@ -27,44 +27,21 @@ public:
 		virtual ~Task()
 		virtual ~Task()
 		{}
 		{}
 
 
-		virtual void operator()() = 0;
+		virtual ANKI_USE_RESULT Error operator()() = 0;
 
 
 	private:
 	private:
 		Task* m_next = nullptr;
 		Task* m_next = nullptr;
 	};
 	};
 
 
-	AsyncLoader(const HeapAllocator<U8>& alloc);
+	AsyncLoader();
 
 
 	~AsyncLoader();
 	~AsyncLoader();
 
 
+	ANKI_USE_RESULT Error create(const HeapAllocator<U8>& alloc);
+
 	/// Create a new asynchronous loading task.
 	/// Create a new asynchronous loading task.
 	template<typename TTask, typename... TArgs>
 	template<typename TTask, typename... TArgs>
-	void newTask(TArgs&&... args)
-	{
-		TTask* newTask = m_alloc.template newInstance<TTask>(
-			std::forward<TArgs>(args)...);
-
-		// Append task to the list
-		{
-			LockGuard<Mutex> lock(m_mtx);
-			if(m_tail != nullptr)
-			{
-				ANKI_ASSERT(m_tail->m_next == nullptr);
-				ANKI_ASSERT(m_head != nullptr);
-
-				m_tail->m_next = newTask;
-				m_tail = newTask;
-			}
-			else
-			{
-				ANKI_ASSERT(m_head == nullptr);
-				m_head = m_tail = newTask;
-			}
-		}
-
-		// Wake up the thread
-		m_condVar.notifyOne();
-	}
+	ANKI_USE_RESULT Error newTask(TArgs&&... args);
 
 
 private:
 private:
 	HeapAllocator<U8> m_alloc;
 	HeapAllocator<U8> m_alloc;
@@ -76,13 +53,47 @@ private:
 	Bool8 m_quit = false;
 	Bool8 m_quit = false;
 
 
 	/// Thread callback
 	/// Thread callback
-	static I threadCallback(Thread::Info& info);
+	static ANKI_USE_RESULT Error threadCallback(Thread::Info& info);
 
 
-	void threadWorker();
+	Error threadWorker();
 
 
 	void stop();
 	void stop();
 };
 };
 
 
+template<typename TTask, typename... TArgs>
+Error AsyncLoader::newTask(TArgs&&... args)
+{
+	TTask* newTask = m_alloc.template newInstance<TTask>(
+		std::forward<TArgs>(args)...);
+	if(newTask == nullptr)
+	{
+		return ErrorCode::OUT_OF_MEMORY;
+	}
+
+	// Append task to the list
+	{
+		LockGuard<Mutex> lock(m_mtx);
+		if(m_tail != nullptr)
+		{
+			ANKI_ASSERT(m_tail->m_next == nullptr);
+			ANKI_ASSERT(m_head != nullptr);
+
+			m_tail->m_next = newTask;
+			m_tail = newTask;
+		}
+		else
+		{
+			ANKI_ASSERT(m_head == nullptr);
+			m_head = m_tail = newTask;
+		}
+	}
+
+	// Wake up the thread
+	m_condVar.notifyOne();
+
+	return ErrorCode::NONE;
+}
+
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 14 - 12
include/anki/scene/ParticleEmitter.h

@@ -156,20 +156,22 @@ class ParticleEmitter: public SceneNode, public SpatialComponent,
 	friend class ParticleSimple;
 	friend class ParticleSimple;
 
 
 public:
 public:
-	ParticleEmitter(
-		const CString& name, SceneGraph* scene, // SceneNode
-		const CString& filename); // Self
+	ParticleEmitter(SceneGraph* scene);
 
 
 	~ParticleEmitter();
 	~ParticleEmitter();
 
 
+	ANKI_USE_RESULT Error create(
+		const CString& name, const CString& filename);
+
 	/// @name SceneNode virtuals
 	/// @name SceneNode virtuals
 	/// @{
 	/// @{
-	void frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(
+		F32 prevUpdateTime, F32 crntTime) override;
 	/// @}
 	/// @}
 
 
 	/// @name MoveComponent virtuals
 	/// @name MoveComponent virtuals
 	/// @{
 	/// @{
-	void onMoveComponentUpdate(
+	ANKI_USE_RESULT Error onMoveComponentUpdate(
 		SceneNode& node, F32 prevTime, F32 crntTime) override;
 		SceneNode& node, F32 prevTime, F32 crntTime) override;
 	/// @}
 	/// @}
 
 
@@ -188,7 +190,7 @@ public:
 
 
 	/// @name RenderComponent virtuals
 	/// @name RenderComponent virtuals
 	/// @{
 	/// @{
-	void buildRendering(RenderingBuildData& data);
+	ANKI_USE_RESULT Error buildRendering(RenderingBuildData& data);
 
 
 	const Material& getMaterial();
 	const Material& getMaterial();
 
 
@@ -206,10 +208,10 @@ private:
 	};
 	};
 
 
 	ParticleEmitterResourcePointer m_particleEmitterResource;
 	ParticleEmitterResourcePointer m_particleEmitterResource;
-	SceneVector<ParticleBase*> m_particles;
-	F32 m_timeLeftForNextEmission;
+	SceneDArray<ParticleBase*> m_particles;
+	F32 m_timeLeftForNextEmission = 0.0;
 	Obb m_obb;
 	Obb m_obb;
-	SceneVector<Transform> m_transforms; ///< InstanceTransforms
+	SceneDArray<Transform> m_transforms; ///< InstanceTransforms
 	Timestamp m_transformsTimestamp = 0;
 	Timestamp m_transformsTimestamp = 0;
 
 
 	// Opt: We dont have to make extra calculations if the ParticleEmitter's
 	// Opt: We dont have to make extra calculations if the ParticleEmitter's
@@ -223,10 +225,10 @@ private:
 
 
 	SimulationType m_simulationType = SimulationType::UNDEFINED;
 	SimulationType m_simulationType = SimulationType::UNDEFINED;
 
 
-	void createParticlesSimulation(SceneGraph* scene);
-	void createParticlesSimpleSimulation(SceneGraph* scene);
+	ANKI_USE_RESULT Error createParticlesSimulation(SceneGraph* scene);
+	ANKI_USE_RESULT Error createParticlesSimpleSimulation();
 
 
-	void doInstancingCalcs();
+	ANKI_USE_RESULT Error doInstancingCalcs();
 };
 };
 
 
 /// @}
 /// @}

+ 23 - 17
include/anki/scene/SceneGraph.h

@@ -26,7 +26,7 @@ class Renderer;
 class ResourceManager;
 class ResourceManager;
 class Camera;
 class Camera;
 
 
-/// @addtogroup Scene
+/// @addtogroup scene
 /// @{
 /// @{
 
 
 /// The scene graph that  all the scene entities
 /// The scene graph that  all the scene entities
@@ -35,13 +35,15 @@ class SceneGraph
 	friend class SceneNode;
 	friend class SceneNode;
 
 
 public:
 public:
-	/// @name Constructors/Destructor
-	/// @{
-	SceneGraph(AllocAlignedCallback allocCb, void* allocCbData, 
-		Threadpool* threadpool, ResourceManager* resources);
+	SceneGraph();
 
 
 	~SceneGraph();
 	~SceneGraph();
-	/// @}
+
+	ANKI_USE_RESULT Error create(
+		AllocAlignedCallback allocCb, 
+		void* allocCbData, 
+		Threadpool* threadpool, 
+		ResourceManager* resources);
 
 
 	/// @note Return a copy
 	/// @note Return a copy
 	SceneAllocator<U8> getAllocator() const
 	SceneAllocator<U8> getAllocator() const
@@ -90,7 +92,7 @@ public:
 
 
 	U32 getSceneNodesCount() const
 	U32 getSceneNodesCount() const
 	{
 	{
-		return m_nodes.size();
+		return m_nodesCount;
 	}
 	}
 
 
 	PhysicsWorld& getPhysics()
 	PhysicsWorld& getPhysics()
@@ -125,10 +127,11 @@ public:
 		return *m_threadpool;
 		return *m_threadpool;
 	}
 	}
 
 
-	void update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer);
+	ANKI_USE_RESULT Error update(
+		F32 prevUpdateTime, F32 crntTime, Renderer& renderer);
 
 
-	SceneNode& findSceneNode(const char* name);
-	SceneNode* tryFindSceneNode(const char* name);
+	SceneNode& findSceneNode(const CString& name);
+	SceneNode* tryFindSceneNode(const CString& name);
 
 
 	/// Iterate the scene nodes using a lambda
 	/// Iterate the scene nodes using a lambda
 	template<typename Func>
 	template<typename Func>
@@ -151,16 +154,18 @@ public:
 	ANKI_USE_RESULT Error iterateSceneNodes(
 	ANKI_USE_RESULT Error iterateSceneNodes(
 		PtrSize begin, PtrSize count, Func func)
 		PtrSize begin, PtrSize count, Func func)
 	{
 	{
-		ANKI_ASSERT(begin < m_nodes.size() && count <= m_nodes.size());
-		for(auto it = m_nodes.begin() + begin; 
-			it != m_nodes.begin() + count; 
-			it++)
+		ANKI_ASSERT(begin < m_nodesCount && count <= m_nodesCount);
+		auto it = m_nodes.getBegin() + begin;
+		
+		while(count-- != 0)
 		{
 		{
 			Error err = func(*(*it));
 			Error err = func(*(*it));
 			if(err)
 			if(err)
 			{
 			{
 				return err;
 				return err;
 			}
 			}
+
+			++it;
 		}
 		}
 
 
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
@@ -231,10 +236,11 @@ private:
 	GlDevice* m_gl = nullptr;
 	GlDevice* m_gl = nullptr;
 
 
 	SceneAllocator<U8> m_alloc;
 	SceneAllocator<U8> m_alloc;
-	SceneAllocator<U8> m_frameAlloc;
+	SceneFrameAllocator<U8> m_frameAlloc;
 
 
-	SceneVector<SceneNode*> m_nodes;
-	SceneDictionary<SceneNode*> m_dict;
+	List<SceneNode*, SceneAllocator<SceneNode*>> m_nodes;
+	U32 m_nodesCount = 0;
+	//SceneDictionary<SceneNode*> m_dict;
 
 
 	Vec3 m_ambientCol = Vec3(1.0); ///< The global ambient color
 	Vec3 m_ambientCol = Vec3(1.0); ///< The global ambient color
 	Timestamp m_ambiendColorUpdateTimestamp = getGlobTimestamp();
 	Timestamp m_ambiendColorUpdateTimestamp = getGlobTimestamp();

+ 13 - 1
include/anki/util/DArray.h

@@ -8,9 +8,20 @@
 
 
 #include "anki/util/Allocator.h"
 #include "anki/util/Allocator.h"
 #include "anki/util/NonCopyable.h"
 #include "anki/util/NonCopyable.h"
+#include "anki/util/ScopeDestroyer.h"
 
 
 namespace anki {
 namespace anki {
 
 
+// Forward
+template<typename T, typename TAlloc>
+class DArray;
+
+/// @addtogroup util_private
+/// @{
+template<typename T, typename TAlloc>
+using DArrayScopeDestroyer = ScopeDestroyer<DArray<T, TAlloc>, TAlloc>;
+/// @}
+
 /// @addtogroup util_containers
 /// @addtogroup util_containers
 /// @{
 /// @{
 
 
@@ -26,6 +37,8 @@ public:
 	using Reference = Value&;
 	using Reference = Value&;
 	using ConstReference = const Value&;
 	using ConstReference = const Value&;
 
 
+	using ScopeDestroyer = DArrayScopeDestroyer<T, TAlloc>;
+
 	// STL compatible
 	// STL compatible
 	using iterator = Iterator;
 	using iterator = Iterator;
 	using const_iterator = ConstIterator;
 	using const_iterator = ConstIterator;
@@ -253,7 +266,6 @@ private:
 		b.m_size = 0;
 		b.m_size = 0;
 	}
 	}
 };
 };
-
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 2
include/anki/util/StringList.h

@@ -71,8 +71,8 @@ public:
 
 
 	/// Split a string using a separator (@a separator) and return these
 	/// Split a string using a separator (@a separator) and return these
 	/// strings in a string list
 	/// strings in a string list
-	static ANKI_USE_RESULT Error splitString(
-		Allocator alloc, const CString& s, const Char separator, Self& out);
+	ANKI_USE_RESULT Error splitString(
+		Allocator alloc, const CString& s, const Char separator);
 };
 };
 
 
 /// A common string list allocated in heap.
 /// A common string list allocated in heap.

+ 6 - 7
include/anki/util/StringList.inl.h

@@ -80,10 +80,9 @@ template<typename TAlloc>
 Error StringListBase<TAlloc>::splitString(
 Error StringListBase<TAlloc>::splitString(
 	Allocator alloc,
 	Allocator alloc,
 	const CString& s, 
 	const CString& s, 
-	const Char separator,
-	Self& out)
+	const Char separator)
 {
 {
-	ANKI_ASSERT(out.isEmpty());
+	ANKI_ASSERT(Base::isEmpty());
 
 
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
 	const Char* begin = &s[0];
 	const Char* begin = &s[0];
@@ -95,7 +94,7 @@ Error StringListBase<TAlloc>::splitString(
 		{
 		{
 			if(begin < end)
 			if(begin < end)
 			{
 			{
-				err = out.emplaceBack(alloc);
+				err = Base::emplaceBack(alloc);
 
 
 				String str;
 				String str;
 				if(!err)
 				if(!err)
@@ -105,7 +104,7 @@ Error StringListBase<TAlloc>::splitString(
 
 
 				if(!err)
 				if(!err)
 				{
 				{
-					out.getBack() = std::move(str);
+					Base::getBack() = std::move(str);
 				}
 				}
 			}
 			}
 
 
@@ -115,7 +114,7 @@ Error StringListBase<TAlloc>::splitString(
 		{
 		{
 			if(begin < end)
 			if(begin < end)
 			{
 			{
-				err = out.emplaceBack(alloc);
+				err = Base::emplaceBack(alloc);
 
 
 				String str;
 				String str;
 				if(!err)
 				if(!err)
@@ -125,7 +124,7 @@ Error StringListBase<TAlloc>::splitString(
 
 
 				if(!err)
 				if(!err)
 				{
 				{
-					out.getBack() = std::move(str);
+					Base::getBack() = std::move(str);
 					begin = end + 1;
 					begin = end + 1;
 				}
 				}
 			}
 			}

+ 15 - 7
src/misc/Xml.cpp

@@ -104,16 +104,19 @@ Error XmlElement::getFloats(DArray<F64, StackAllocator<F64>>& out) const
 	StringListBase<StackAllocator<char>> list;
 	StringListBase<StackAllocator<char>> list;
 	if(!err)
 	if(!err)
 	{
 	{
-		 list = StringListBase<StackAllocator<char>>(
-			StringListBase<StackAllocator<char>>::splitString(
-			CString(txt), ' ', m_alloc));
+		err = list.splitString(m_alloc, txt, ' ');
+	}
 
 
-		err = out.create(m_alloc, list.size());
+	if(!err)
+	{
+		err = out.create(m_alloc, list.getSize());
 	}
 	}
 
 
+	auto it = list.getBegin();
 	for(U i = 0; i < out.getSize() && !err; i++)
 	for(U i = 0; i < out.getSize() && !err; i++)
 	{
 	{
-		err = list[i].toF64(out[i]);
+		err = it->toF64(out[i]);
+		++it;
 	}
 	}
 
 
 	if(err)
 	if(err)
@@ -121,6 +124,8 @@ Error XmlElement::getFloats(DArray<F64, StackAllocator<F64>>& out) const
 		ANKI_LOGE("Failed to return floats. Element: %s", m_el->Value());
 		ANKI_LOGE("Failed to return floats. Element: %s", m_el->Value());
 	}
 	}
 
 
+	list.destroy(m_alloc);
+
 	return err;
 	return err;
 }
 }
 
 
@@ -314,8 +319,9 @@ Error XmlDocument::loadFile(const CString& filename, StackAllocator<U8>& alloc)
 	}
 	}
 
 
 	m_alloc = alloc;
 	m_alloc = alloc;
-	StringBase<StackAllocator<char>> text(m_alloc);
-	err = file.readAllText(text);
+	StringBase<StackAllocator<char>> text;
+	
+	err = file.readAllText(StackAllocator<char>(m_alloc), text);
 	if(err)
 	if(err)
 	{
 	{
 		return err;
 		return err;
@@ -328,6 +334,8 @@ Error XmlDocument::loadFile(const CString& filename, StackAllocator<U8>& alloc)
 			? "unknown" : m_doc.GetErrorStr1()));
 			? "unknown" : m_doc.GetErrorStr1()));
 	}
 	}
 
 
+	text.destroy(m_alloc);
+
 	return err;
 	return err;
 }
 }
 
 

+ 22 - 13
src/renderer/Bs.cpp

@@ -15,33 +15,42 @@ Bs::~Bs()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Bs::init(const ConfigSet&)
+Error Bs::init(const ConfigSet&)
 {
 {
-	// Do nothing
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Bs::run(GlCommandBufferHandle& jobs)
+Error Bs::run(GlCommandBufferHandle& cmdb)
 {
 {
-	jobs.enableDepthTest(true);
-	jobs.setDepthWriteMask(false);
-	jobs.enableBlend(true);
+	Error err = ErrorCode::NONE;
+
+	cmdb.enableDepthTest(true);
+	cmdb.setDepthWriteMask(false);
+	cmdb.enableBlend(true);
 
 
 	RenderableDrawer& drawer = m_r->getSceneDrawer();
 	RenderableDrawer& drawer = m_r->getSceneDrawer();
-	drawer.prepareDraw(RenderingStage::BLEND, Pass::COLOR, jobs);
+	drawer.prepareDraw(RenderingStage::BLEND, Pass::COLOR, cmdb);
 
 
 	Camera& cam = m_r->getSceneGraph().getActiveCamera();
 	Camera& cam = m_r->getSceneGraph().getActiveCamera();
 
 
-	for(auto& it : cam.getVisibilityTestResults().m_renderables)
+	auto it = cam.getVisibilityTestResults().getRenderablesBegin();
+	auto end = cam.getVisibilityTestResults().getRenderablesEnd();
+	for(; !err && it != end; ++it)
 	{
 	{
-		drawer.render(cam, it);
+		err = drawer.render(cam, *it);
 	}
 	}
 
 
-	drawer.finishDraw();
+	if(!err)
+	{
+		drawer.finishDraw();
+
+		cmdb.enableDepthTest(false);
+		cmdb.setDepthWriteMask(true);
+		cmdb.enableBlend(false);
+	}
 
 
-	jobs.enableDepthTest(false);
-	jobs.setDepthWriteMask(true);
-	jobs.enableBlend(false);
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 62 - 27
src/renderer/Dbg.cpp

@@ -30,45 +30,71 @@ Dbg::~Dbg()
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Dbg::init(const ConfigSet& initializer)
+Error Dbg::init(const ConfigSet& initializer)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_enabled = initializer.get("dbg.enabled");
 	m_enabled = initializer.get("dbg.enabled");
 	enableBits(Flag::ALL);
 	enableBits(Flag::ALL);
 
 
-	try
+	GlDevice& gl = getGlDevice();
+	GlCommandBufferHandle cmdb;
+	err = cmdb.create(&gl);
+	if(err)
 	{
 	{
-		GlDevice& gl = getGlDevice();
-		GlCommandBufferHandle cmdb;
-		cmdb.create(&gl);
+		return err;
+	}
 
 
-		// Chose the correct color FAI
-		if(m_r->getPps().getEnabled())
-		{
-			m_fb.create(cmdb, 
-				{{m_r->getPps()._getRt(), GL_COLOR_ATTACHMENT0},
-				{m_r->getMs()._getDepthRt(), GL_DEPTH_ATTACHMENT}});
-		}
-		else
+	// Chose the correct color FAI
+	if(m_r->getPps().getEnabled())
+	{
+		err = m_fb.create(cmdb, 
+			{{m_r->getPps()._getRt(), GL_COLOR_ATTACHMENT0},
+			{m_r->getMs()._getDepthRt(), GL_DEPTH_ATTACHMENT}});
+	}
+	else
+	{
+		err = m_fb.create(cmdb, 
+			{{m_r->getIs()._getRt(), GL_COLOR_ATTACHMENT0},
+			{m_r->getMs()._getDepthRt(), GL_DEPTH_ATTACHMENT}});
+	}
+
+	if(!err)
+	{
+		m_drawer = getAllocator().newInstance<DebugDrawer>();
+		if(m_drawer == nullptr)
 		{
 		{
-			m_fb.create(cmdb, 
-				{{m_r->getIs()._getRt(), GL_COLOR_ATTACHMENT0},
-				{m_r->getMs()._getDepthRt(), GL_DEPTH_ATTACHMENT}});
+			err = ErrorCode::OUT_OF_MEMORY;
 		}
 		}
+	}
 
 
-		m_drawer = getAllocator().newInstance<DebugDrawer>(m_r);
-		m_sceneDrawer = getAllocator().newInstance<SceneDebugDrawer>(m_drawer);
+	if(!err)
+	{
+		err = m_drawer->create(m_r);
+	}
 
 
-		cmdb.finish();
+	if(!err)
+	{
+		m_sceneDrawer = getAllocator().newInstance<SceneDebugDrawer>(m_drawer);
+		if(m_sceneDrawer == nullptr)
+		{
+			err = ErrorCode::OUT_OF_MEMORY;
+		}
 	}
 	}
-	catch(std::exception& e)
+
+	if(!err)
 	{
 	{
-		throw ANKI_EXCEPTION("Cannot create debug FBO") << e;
+		cmdb.finish();
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Dbg::run(GlCommandBufferHandle& cmdb)
+Error Dbg::run(GlCommandBufferHandle& cmdb)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
 
 
 	SceneGraph& scene = m_r->getSceneGraph();
 	SceneGraph& scene = m_r->getSceneGraph();
@@ -82,21 +108,25 @@ void Dbg::run(GlCommandBufferHandle& cmdb)
 	m_drawer->setModelMatrix(Mat4::getIdentity());
 	m_drawer->setModelMatrix(Mat4::getIdentity());
 	//drawer->drawGrid();
 	//drawer->drawGrid();
 
 
-	scene.iterateSceneNodes([&](SceneNode& node)
+	err = scene.iterateSceneNodes([&](SceneNode& node) -> Error
 	{
 	{
 		SpatialComponent* sp = node.tryGetComponent<SpatialComponent>();
 		SpatialComponent* sp = node.tryGetComponent<SpatialComponent>();
 
 
 		if(&cam.getComponent<SpatialComponent>() == sp)
 		if(&cam.getComponent<SpatialComponent>() == sp)
 		{
 		{
-			return;
+			return ErrorCode::NONE	;
 		}
 		}
 
 
 		if(bitsEnabled(Flag::SPATIAL) && sp)
 		if(bitsEnabled(Flag::SPATIAL) && sp)
 		{
 		{
 			m_sceneDrawer->draw(node);
 			m_sceneDrawer->draw(node);
 		}
 		}
+
+		return ErrorCode::NONE;
 	});
 	});
 
 
+	(void)err;
+
 	// XXX
 	// XXX
 #if 0
 #if 0
 	if(0)
 	if(0)
@@ -410,10 +440,15 @@ void Dbg::run(GlCommandBufferHandle& cmdb)
 	}
 	}
 #endif
 #endif
 
 
-	m_drawer->flush();
-	m_drawer->finishDraw();
+	err = m_drawer->flush();
+
+	if(!err)
+	{
+		m_drawer->finishDraw();
+		cmdb.enableDepthTest(false);
+	}
 
 
-	cmdb.enableDepthTest(false);
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 73 - 27
src/renderer/DebugDrawer.cpp

@@ -19,35 +19,60 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-DebugDrawer::DebugDrawer(Renderer* r)
+DebugDrawer::DebugDrawer()
+{}
+
+//==============================================================================
+DebugDrawer::~DebugDrawer()
+{}
+
+//==============================================================================
+Error DebugDrawer::create(Renderer* r)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	GlDevice& gl = r->_getGlDevice();
 	GlDevice& gl = r->_getGlDevice();
 
 
-	m_vert.load("shaders/Dbg.vert.glsl", &r->_getResourceManager());
-	m_frag.load("shaders/Dbg.frag.glsl", &r->_getResourceManager());
+	err = m_vert.load("shaders/Dbg.vert.glsl", &r->_getResourceManager());
+
+	if(!err)
+	{
+		err = m_frag.load("shaders/Dbg.frag.glsl", &r->_getResourceManager());
+	}
 
 
 	GlCommandBufferHandle jobs;
 	GlCommandBufferHandle jobs;
-	jobs.create(&gl);
 
 
-	m_ppline.create(jobs, 
-		{m_vert->getGlProgram(), m_frag->getGlProgram()});
+	if(!err)
+	{
+		err = jobs.create(&gl);
+	}
 
 
-	m_vertBuff.create(jobs, GL_ARRAY_BUFFER, 
-		sizeof(m_clientLineVerts), GL_DYNAMIC_STORAGE_BIT);
+	if(!err)
+	{
+		err = m_ppline.create(jobs, 
+			{m_vert->getGlProgram(), m_frag->getGlProgram()});
+	}
 
 
-	m_lineVertCount = 0;
-	m_triVertCount = 0;
-	m_mMat.setIdentity();
-	m_vpMat.setIdentity();
-	m_mvpMat.setIdentity();
-	m_crntCol = Vec3(1.0, 0.0, 0.0);
+	if(!err)
+	{
+		err = m_vertBuff.create(jobs, GL_ARRAY_BUFFER, 
+			sizeof(m_clientLineVerts), GL_DYNAMIC_STORAGE_BIT);
+	}
 
 
-	jobs.finish();
-}
+	if(!err)
+	{
+		m_lineVertCount = 0;
+		m_triVertCount = 0;
+		m_mMat.setIdentity();
+		m_vpMat.setIdentity();
+		m_mvpMat.setIdentity();
+		m_crntCol = Vec3(1.0, 0.0, 0.0);
 
 
-//==============================================================================
-DebugDrawer::~DebugDrawer()
-{}
+		jobs.finish();
+	}
+
+	return err;
+}
 
 
 //==============================================================================
 //==============================================================================
 void DebugDrawer::setModelMatrix(const Mat4& m)
 void DebugDrawer::setModelMatrix(const Mat4& m)
@@ -93,20 +118,28 @@ void DebugDrawer::end()
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void DebugDrawer::flush()
+Error DebugDrawer::flush()
 {
 {
-	flushInternal(GL_LINES);
-	flushInternal(GL_TRIANGLES);
+	Error err = flushInternal(GL_LINES);
+
+	if(!err)
+	{
+		err = flushInternal(GL_TRIANGLES);
+	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void DebugDrawer::flushInternal(GLenum primitive)
+Error DebugDrawer::flushInternal(GLenum primitive)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	if((primitive == GL_LINES && m_lineVertCount == 0)
 	if((primitive == GL_LINES && m_lineVertCount == 0)
 		|| (primitive == GL_TRIANGLES && m_triVertCount == 0))
 		|| (primitive == GL_TRIANGLES && m_triVertCount == 0))
 	{
 	{
 		// Early exit
 		// Early exit
-		return;
+		return ErrorCode::NONE;
 	}
 	}
 
 
 	U clientVerts;
 	U clientVerts;
@@ -127,7 +160,12 @@ void DebugDrawer::flushInternal(GLenum primitive)
 	U size = sizeof(Vertex) * clientVerts;
 	U size = sizeof(Vertex) * clientVerts;
 
 
 	GlClientBufferHandle tmpBuff;
 	GlClientBufferHandle tmpBuff;
-	tmpBuff.create(m_jobs, size, nullptr);
+	err = tmpBuff.create(m_jobs, size, nullptr);
+	if(err)
+	{
+		return err;
+	}
+
 	memcpy(tmpBuff.getBaseAddress(), vertBuff, size);
 	memcpy(tmpBuff.getBaseAddress(), vertBuff, size);
 
 
 	m_vertBuff.write(m_jobs, tmpBuff, 0, 0, size);
 	m_vertBuff.write(m_jobs, tmpBuff, 0, 0, size);
@@ -141,6 +179,8 @@ void DebugDrawer::flushInternal(GLenum primitive)
 		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
 		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
 
 
 	m_jobs.drawArrays(primitive, clientVerts);
 	m_jobs.drawArrays(primitive, clientVerts);
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -166,7 +206,9 @@ void DebugDrawer::pushBackVertex(const Vec3& pos)
 
 
 	if(*vertCount == MAX_POINTS_PER_DRAW)
 	if(*vertCount == MAX_POINTS_PER_DRAW)
 	{
 	{
-		flush();
+		Error err = flush();
+		// TODO Don't ignore
+		(void)err;
 	}
 	}
 }
 }
 
 
@@ -454,10 +496,14 @@ void SceneDebugDrawer::draw(SceneNode& node)
 		draw(*fr);
 		draw(*fr);
 	}
 	}
 
 
-	node.iterateComponentsOfType<SpatialComponent>([&](SpatialComponent& sp)
+	Error err = node.iterateComponentsOfType<SpatialComponent>(
+		[&](SpatialComponent& sp) -> Error
 	{
 	{
 		draw(sp);
 		draw(sp);
+		return ErrorCode::NONE;
 	});
 	});
+
+	(void)err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 34 - 10
src/renderer/Drawer.cpp

@@ -47,7 +47,7 @@ public:
 	}
 	}
 
 
 	template<typename TRenderableVariableTemplate>
 	template<typename TRenderableVariableTemplate>
-	void visit(const TRenderableVariableTemplate& rvar)
+	Error visit(const TRenderableVariableTemplate& rvar)
 	{
 	{
 		typedef typename TRenderableVariableTemplate::Type DataType;
 		typedef typename TRenderableVariableTemplate::Type DataType;
 		const GlProgramVariable& glvar = rvar.getGlProgramVariable();
 		const GlProgramVariable& glvar = rvar.getGlProgramVariable();
@@ -208,6 +208,8 @@ public:
 			ANKI_ASSERT(0);
 			ANKI_ASSERT(0);
 			break;
 			break;
 		}
 		}
+
+		return ErrorCode::NONE;
 	}
 	}
 };
 };
 
 
@@ -225,15 +227,28 @@ void SetupRenderableVariableVisitor::uniSet<TextureResourcePointer>(
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-RenderableDrawer::RenderableDrawer(Renderer* r)
-:	m_r(r)
+Error RenderableDrawer::create(Renderer* r)
 {
 {
+	Error err = ErrorCode::NONE;
+
+	m_r = r;
+
 	// Create the uniform buffer
 	// Create the uniform buffer
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&m_r->_getGlDevice());
-	m_uniformBuff.create(cmdBuff, GL_UNIFORM_BUFFER, 
+	err = cmdBuff.create(&m_r->_getGlDevice());
+	if(err)
+	{
+		return err;
+	}
+
+	err = m_uniformBuff.create(cmdBuff, GL_UNIFORM_BUFFER, 
 		MAX_UNIFORM_BUFFER_SIZE,
 		MAX_UNIFORM_BUFFER_SIZE,
 		GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
 		GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
+	if(err)
+	{
+		return err;
+	}
+
 	cmdBuff.flush();
 	cmdBuff.flush();
 
 
 	m_uniformPtr = (U8*)m_uniformBuff.getPersistentMappingAddress();
 	m_uniformPtr = (U8*)m_uniformBuff.getPersistentMappingAddress();
@@ -244,6 +259,8 @@ RenderableDrawer::RenderableDrawer(Renderer* r)
 	// Set some other values
 	// Set some other values
 	m_uniformsUsedSize = 0;
 	m_uniformsUsedSize = 0;
 	m_uniformsUsedSizeFrame = 0;
 	m_uniformsUsedSizeFrame = 0;
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -289,7 +306,8 @@ void RenderableDrawer::setupUniforms(
 		RenderComponentVariable* rvar = *it;
 		RenderComponentVariable* rvar = *it;
 
 
 		vis.m_rvar = rvar;
 		vis.m_rvar = rvar;
-		rvar->acceptVisitor(vis);
+		Error err = rvar->acceptVisitor(vis);
+		(void)err;
 	}
 	}
 
 
 	// Update the uniform descriptor
 	// Update the uniform descriptor
@@ -306,7 +324,7 @@ void RenderableDrawer::setupUniforms(
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
+Error RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
 {
 {
 	RenderingBuildData build;
 	RenderingBuildData build;
 
 
@@ -342,14 +360,14 @@ void RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
 	{
 	{
 		if(m_stage == RenderingStage::BLEND)
 		if(m_stage == RenderingStage::BLEND)
 		{
 		{
-			return;
+			return ErrorCode::NONE;
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		if(m_stage != RenderingStage::BLEND)
 		if(m_stage != RenderingStage::BLEND)
 		{
 		{
-			return;
+			return ErrorCode::NONE;
 		}
 		}
 
 
 		m_cmdBuff.setBlendFunctions(
 		m_cmdBuff.setBlendFunctions(
@@ -371,13 +389,19 @@ void RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
 	build.m_subMeshIndicesCount = visibleNode.m_spatialsCount;
 	build.m_subMeshIndicesCount = visibleNode.m_spatialsCount;
 	build.m_jobs = m_cmdBuff;
 	build.m_jobs = m_cmdBuff;
 
 
-	renderable.buildRendering(build);
+	Error err = renderable.buildRendering(build);
+	if(err)
+	{
+		return err;
+	}
 
 
 	// Wireframe back to what it was
 	// Wireframe back to what it was
 	if(wireframeOn)
 	if(wireframeOn)
 	{
 	{
 		m_cmdBuff.setPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		m_cmdBuff.setPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 	}
 	}
+
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 16 - 8
src/renderer/Ez.cpp

@@ -13,37 +13,45 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-void Ez::init(const ConfigSet& config)
+Error Ez::init(const ConfigSet& config)
 {
 {
 	m_enabled = config.get("ms.ez.enabled");
 	m_enabled = config.get("ms.ez.enabled");
 	m_maxObjectsToDraw = config.get("ms.ez.maxObjectsToDraw");
 	m_maxObjectsToDraw = config.get("ms.ez.maxObjectsToDraw");
+
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ez::run(GlCommandBufferHandle& cmdBuff)
+Error Ez::run(GlCommandBufferHandle& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
 
 
+	Error err = ErrorCode::NONE;
 	SceneGraph& scene = m_r->getSceneGraph();
 	SceneGraph& scene = m_r->getSceneGraph();
 	Camera& cam = scene.getActiveCamera();
 	Camera& cam = scene.getActiveCamera();
 
 
-	VisibilityTestResults& vi = cam.getVisibilityTestResults();
-
 	m_r->getSceneDrawer().prepareDraw(
 	m_r->getSceneDrawer().prepareDraw(
 		RenderingStage::MATERIAL, Pass::DEPTH, cmdBuff);
 		RenderingStage::MATERIAL, Pass::DEPTH, cmdBuff);
 
 
 	U count = m_maxObjectsToDraw;
 	U count = m_maxObjectsToDraw;
-	for(auto& it : vi.m_renderables)
+	auto it = cam.getVisibilityTestResults().getRenderablesBegin();
+	auto end = cam.getVisibilityTestResults().getRenderablesEnd();
+	for(; it != end; ++it)
 	{
 	{
-		m_r->getSceneDrawer().render(cam, it);
+		err = m_r->getSceneDrawer().render(cam, *it);
 
 
-		if(--count == 0)
+		if(--count == 0 || err)
 		{
 		{
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
-	m_r->getSceneDrawer().finishDraw();
+	if(!err)
+	{
+		m_r->getSceneDrawer().finishDraw();
+	}
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 80 - 37
src/renderer/Hdr.cpp

@@ -14,31 +14,40 @@ Hdr::~Hdr()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Hdr::initFb(GlFramebufferHandle& fb, GlTextureHandle& rt)
+Error Hdr::initFb(GlFramebufferHandle& fb, GlTextureHandle& rt)
 {
 {
-	GlDevice& gl = getGlDevice();
+	Error err = ErrorCode::NONE;
 
 
-	m_r->createRenderTarget(m_width, m_height, GL_RGB8, GL_RGB, 
+	err = m_r->createRenderTarget(m_width, m_height, GL_RGB8, GL_RGB, 
 		GL_UNSIGNED_BYTE, 1, rt);
 		GL_UNSIGNED_BYTE, 1, rt);
+	if(err) return err;
 
 
 	// Set to bilinear because the blurring techniques take advantage of that
 	// Set to bilinear because the blurring techniques take advantage of that
 	GlCommandBufferHandle cmdb;
 	GlCommandBufferHandle cmdb;
-	cmdb.create(&gl);
+	err = cmdb.create(&getGlDevice());
+	if(err) return err;
+
 	rt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
 	rt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
 
 
 	// Create FB
 	// Create FB
-	fb.create(cmdb, {{rt, GL_COLOR_ATTACHMENT0}});
+	err = fb.create(cmdb, {{rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
+
 	cmdb.finish();
 	cmdb.finish();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Hdr::initInternal(const ConfigSet& initializer)
+Error Hdr::initInternal(const ConfigSet& initializer)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_enabled = initializer.get("pps.hdr.enabled");
 	m_enabled = initializer.get("pps.hdr.enabled");
 
 
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return ErrorCode::NONE;
 	}
 	}
 
 
 	const F32 renderingQuality = initializer.get("pps.hdr.renderingQuality");
 	const F32 renderingQuality = initializer.get("pps.hdr.renderingQuality");
@@ -53,80 +62,102 @@ void Hdr::initInternal(const ConfigSet& initializer)
 	m_blurringIterationsCount = 
 	m_blurringIterationsCount = 
 		initializer.get("pps.hdr.blurringIterationsCount");
 		initializer.get("pps.hdr.blurringIterationsCount");
 
 
-	initFb(m_hblurFb, m_hblurRt);
-	initFb(m_vblurFb, m_vblurRt);
+	err = initFb(m_hblurFb, m_hblurRt);
+	if(err) return err;
+
+	err = initFb(m_vblurFb, m_vblurRt);
+	if(err) return err;
 
 
 	// init shaders
 	// init shaders
 	GlDevice& gl = getGlDevice();
 	GlDevice& gl = getGlDevice();
 	GlCommandBufferHandle cmdb;
 	GlCommandBufferHandle cmdb;
-	cmdb.create(&gl);
+	err = cmdb.create(&gl);
+	if(err) return err;
 
 
-	m_commonBuff.create(cmdb, GL_UNIFORM_BUFFER, 
+	err = m_commonBuff.create(cmdb, GL_UNIFORM_BUFFER, 
 		sizeof(Vec4), GL_DYNAMIC_STORAGE_BIT);
 		sizeof(Vec4), GL_DYNAMIC_STORAGE_BIT);
+	if(err) return err;
 
 
-	updateDefaultBlock(cmdb);
+	err = updateDefaultBlock(cmdb);
+	if(err) return err;
 
 
 	cmdb.flush();
 	cmdb.flush();
 
 
-	m_toneFrag.load("shaders/PpsHdr.frag.glsl", &getResourceManager());
+	err = m_toneFrag.load("shaders/PpsHdr.frag.glsl", &getResourceManager());
+	if(err) return err;
 
 
-	m_tonePpline = 
-		m_r->createDrawQuadProgramPipeline(m_toneFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_toneFrag->getGlProgram(), m_tonePpline);
+	if(err) return err;
 
 
 	const char* SHADER_FILENAME = 
 	const char* SHADER_FILENAME = 
 		"shaders/VariableSamplingBlurGeneric.frag.glsl";
 		"shaders/VariableSamplingBlurGeneric.frag.glsl";
 
 
-	String pps(getAllocator());
-	pps.sprintf("#define HPASS\n"
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
+	err = pps.sprintf(getAllocator(),
+		"#define HPASS\n"
 		"#define COL_RGB\n"
 		"#define COL_RGB\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES %u\n",
 		"#define SAMPLES %u\n",
 		m_blurringDist, m_height, 
 		m_blurringDist, m_height, 
 		static_cast<U>(initializer.get("pps.hdr.samples")));
 		static_cast<U>(initializer.get("pps.hdr.samples")));
+	if(err) return err;
 
 
-	m_hblurFrag.loadToCache(&getResourceManager(),
+	err = m_hblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_");
 		SHADER_FILENAME, pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_hblurPpline = 
-		m_r->createDrawQuadProgramPipeline(m_hblurFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_hblurFrag->getGlProgram(), m_hblurPpline);
+	if(err) return err;
 
 
-	pps.sprintf("#define VPASS\n"
+	pps.destroy(getAllocator());
+	err = pps.sprintf(getAllocator(),
+		"#define VPASS\n"
 		"#define COL_RGB\n"
 		"#define COL_RGB\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES %u\n",
 		"#define SAMPLES %u\n",
 		m_blurringDist, m_width, 
 		m_blurringDist, m_width, 
 		static_cast<U>(initializer.get("pps.hdr.samples")));
 		static_cast<U>(initializer.get("pps.hdr.samples")));
+	if(err) return err;
 
 
-	m_vblurFrag.loadToCache(&getResourceManager(),
+	err = m_vblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_");
 		SHADER_FILENAME, pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_vblurPpline = 
-		m_r->createDrawQuadProgramPipeline(m_vblurFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_vblurFrag->getGlProgram(), m_vblurPpline);
+	if(err) return err;
 
 
 	// Set timestamps
 	// Set timestamps
 	m_parameterUpdateTimestamp = getGlobTimestamp();
 	m_parameterUpdateTimestamp = getGlobTimestamp();
 	m_commonUboUpdateTimestamp = getGlobTimestamp();
 	m_commonUboUpdateTimestamp = getGlobTimestamp();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Hdr::init(const ConfigSet& initializer)
+Error Hdr::init(const ConfigSet& initializer)
 {
 {
-	try
-	{
-		initInternal(initializer);
-	}
-	catch(const std::exception& e)
+
+	Error err = initInternal(initializer);
+
+	if(err)
 	{
 	{
-		throw ANKI_EXCEPTION("Failed to init PPS HDR") << e;
+		ANKI_LOGE("Failed to init PPS HDR");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Hdr::run(GlCommandBufferHandle& cmdb)
+Error Hdr::run(GlCommandBufferHandle& cmdb)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	// For the passes it should be NEAREST
 	// For the passes it should be NEAREST
 	//vblurFai.setFiltering(Texture::TFrustumType::NEAREST);
 	//vblurFai.setFiltering(Texture::TFrustumType::NEAREST);
@@ -138,7 +169,12 @@ void Hdr::run(GlCommandBufferHandle& cmdb)
 
 
 	if(m_parameterUpdateTimestamp > m_commonUboUpdateTimestamp)
 	if(m_parameterUpdateTimestamp > m_commonUboUpdateTimestamp)
 	{
 	{
-		updateDefaultBlock(cmdb);
+		err = updateDefaultBlock(cmdb);
+		if(err)
+		{
+			return err;
+		}
+
 		m_commonUboUpdateTimestamp = getGlobTimestamp();
 		m_commonUboUpdateTimestamp = getGlobTimestamp();
 	}
 	}
 
 
@@ -169,17 +205,24 @@ void Hdr::run(GlCommandBufferHandle& cmdb)
 
 
 	// For the next stage it should be LINEAR though
 	// For the next stage it should be LINEAR though
 	//vblurFai.setFiltering(Texture::TFrustumType::LINEAR);
 	//vblurFai.setFiltering(Texture::TFrustumType::LINEAR);
+
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Hdr::updateDefaultBlock(GlCommandBufferHandle& cmdb)
+Error Hdr::updateDefaultBlock(GlCommandBufferHandle& cmdb)
 {
 {
 	GlClientBufferHandle tempBuff;
 	GlClientBufferHandle tempBuff;
-	tempBuff.create(cmdb, sizeof(Vec4), nullptr);
+	Error err = tempBuff.create(cmdb, sizeof(Vec4), nullptr);
 	
 	
-	*((Vec4*)tempBuff.getBaseAddress()) = Vec4(m_exposure, 0.0, 0.0, 0.0);
+	if(!err)
+	{
+		*((Vec4*)tempBuff.getBaseAddress()) = Vec4(m_exposure, 0.0, 0.0, 0.0);
+
+		m_commonBuff.write(cmdb, tempBuff, 0, 0, tempBuff.getSize());
+	}
 
 
-	m_commonBuff.write(cmdb, tempBuff, 0, 0, tempBuff.getSize());
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 81 - 42
src/renderer/Is.cpp

@@ -99,7 +99,7 @@ public:
 	/// Bin lights on CPU path
 	/// Bin lights on CPU path
 	Bool m_binLights = true;
 	Bool m_binLights = true;
 
 
-	void operator()(U32 threadId, PtrSize threadsCount)
+	Error operator()(U32 threadId, PtrSize threadsCount)
 	{
 	{
 		U ligthsCount = m_lightsEnd - m_lightsBegin;
 		U ligthsCount = m_lightsEnd - m_lightsBegin;
 
 
@@ -141,6 +141,8 @@ public:
 				break;
 				break;
 			}
 			}
 		}
 		}
+
+		return ErrorCode::NONE;
 	}
 	}
 
 
 	/// Copy CPU light to GPU buffer
 	/// Copy CPU light to GPU buffer
@@ -366,7 +368,8 @@ public:
 
 
 //==============================================================================
 //==============================================================================
 Is::Is(Renderer* r)
 Is::Is(Renderer* r)
-	: RenderingPass(r), m_sm(r)
+:	RenderingPass(r), 
+	m_sm(r)
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
@@ -374,21 +377,24 @@ Is::~Is()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Is::init(const ConfigSet& config)
+Error Is::init(const ConfigSet& config)
 {
 {
-	try
-	{
-		initInternal(config);
-	}
-	catch(const std::exception& e)
+
+	Error err = initInternal(config);
+	
+	if(err)
 	{
 	{
-		throw ANKI_EXCEPTION("Failed to init IS") << e;
+		ANKI_LOGE("Failed to init IS");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::initInternal(const ConfigSet& config)
+Error Is::initInternal(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_groundLightEnabled = config.get("is.groundLightEnabled");
 	m_groundLightEnabled = config.get("is.groundLightEnabled");
 	m_maxPointLights = config.get("is.maxPointLights");
 	m_maxPointLights = config.get("is.maxPointLights");
 	m_maxSpotLights = config.get("is.maxSpotLights");
 	m_maxSpotLights = config.get("is.maxSpotLights");
@@ -396,7 +402,8 @@ void Is::initInternal(const ConfigSet& config)
 
 
 	if(m_maxPointLights < 1 || m_maxSpotLights < 1 || m_maxSpotTexLights < 1)
 	if(m_maxPointLights < 1 || m_maxSpotLights < 1 || m_maxSpotTexLights < 1)
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect number of max lights");
+		ANKI_LOGE("Incorrect number of max lights");
+		return ErrorCode::USER_DATA;
 	}
 	}
 
 
 	m_maxPointLightsPerTile = config.get("is.maxPointLightsPerTile");
 	m_maxPointLightsPerTile = config.get("is.maxPointLightsPerTile");
@@ -410,7 +417,8 @@ void Is::initInternal(const ConfigSet& config)
 		|| m_maxSpotLightsPerTile % 4 != 0
 		|| m_maxSpotLightsPerTile % 4 != 0
 		|| m_maxSpotTexLightsPerTile % 4 != 0)
 		|| m_maxSpotTexLightsPerTile % 4 != 0)
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect number of max lights per tile");
+		ANKI_LOGE("Incorrect number of max lights per tile");
+		return ErrorCode::USER_DATA;
 	}
 	}
 
 
 	m_tileSize = calcTileSize();
 	m_tileSize = calcTileSize();
@@ -418,14 +426,17 @@ void Is::initInternal(const ConfigSet& config)
 	//
 	//
 	// Init the passes
 	// Init the passes
 	//
 	//
-	m_sm.init(config);
+	err = m_sm.init(config);
+	if(err) return err;
 
 
 	//
 	//
 	// Load the programs
 	// Load the programs
 	//
 	//
-	String pps(getAllocator());
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
 
 
-	pps.sprintf(
+	err = pps.sprintf(
+		getAllocator(),
 		"\n#define TILES_X_COUNT %u\n"
 		"\n#define TILES_X_COUNT %u\n"
 		"#define TILES_Y_COUNT %u\n"
 		"#define TILES_Y_COUNT %u\n"
 		"#define TILES_COUNT %u\n" 
 		"#define TILES_COUNT %u\n" 
@@ -454,28 +465,35 @@ void Is::initInternal(const ConfigSet& config)
 		m_groundLightEnabled,
 		m_groundLightEnabled,
 		TILES_BLOCK_BINDING,
 		TILES_BLOCK_BINDING,
 		m_sm.getPoissonEnabled());
 		m_sm.getPoissonEnabled());
+	if(err) return err;
 
 
 	// point light
 	// point light
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice()); // Job for initialization
+	err = cmdBuff.create(&getGlDevice()); // Job for initialization
+	if(err) return err;
 
 
-	m_lightVert.loadToCache(&getResourceManager(),
+	err = m_lightVert.loadToCache(&getResourceManager(),
 		"shaders/IsLp.vert.glsl", pps.toCString(), "r_");
 		"shaders/IsLp.vert.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_lightFrag.loadToCache(&getResourceManager(),
+	err = m_lightFrag.loadToCache(&getResourceManager(),
 		"shaders/IsLp.frag.glsl", pps.toCString(), "r_");
 		"shaders/IsLp.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_lightPpline.create(cmdBuff, 
+	err = m_lightPpline.create(cmdBuff, 
 		{m_lightVert->getGlProgram(), m_lightFrag->getGlProgram()});
 		{m_lightVert->getGlProgram(), m_lightFrag->getGlProgram()});
+	if(err) return err;
 
 
 	//
 	//
 	// Create framebuffer
 	// Create framebuffer
 	//
 	//
 
 
-	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGB8,
+	err = m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGB8,
 			GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt);
 			GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt);
+	if(err) return err;
 
 
-	m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	err = m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
 
 
 	//
 	//
 	// Init the quad
 	// Init the quad
@@ -484,33 +502,41 @@ void Is::initInternal(const ConfigSet& config)
 		{1.0, 0.0}, {0.0, 0.0}};
 		{1.0, 0.0}, {0.0, 0.0}};
 
 
 	GlClientBufferHandle tempBuff;
 	GlClientBufferHandle tempBuff;
-	tempBuff.create(cmdBuff, sizeof(quadVertCoords), 
+	err = tempBuff.create(cmdBuff, sizeof(quadVertCoords), 
 		(void*)&quadVertCoords[0][0]);
 		(void*)&quadVertCoords[0][0]);
+	if(err) return err;
 
 
-	m_quadPositionsVertBuff.create(cmdBuff, GL_ARRAY_BUFFER, tempBuff, 0);
+	err = m_quadPositionsVertBuff.create(cmdBuff, GL_ARRAY_BUFFER, tempBuff, 0);
+	if(err) return err;
 
 
 	//
 	//
 	// Create UBOs
 	// Create UBOs
 	//
 	//
 	const GLbitfield bufferBits = GL_DYNAMIC_STORAGE_BIT;
 	const GLbitfield bufferBits = GL_DYNAMIC_STORAGE_BIT;
 
 
-	m_commonBuff.create(cmdBuff, GL_UNIFORM_BUFFER, 
+	err = m_commonBuff.create(cmdBuff, GL_UNIFORM_BUFFER, 
 		sizeof(shader::CommonUniforms), bufferBits);
 		sizeof(shader::CommonUniforms), bufferBits);
+	if(err) return err;
 
 
-	m_lightsBuff.create(cmdBuff, GL_SHADER_STORAGE_BUFFER, 
+	err = m_lightsBuff.create(cmdBuff, GL_SHADER_STORAGE_BUFFER, 
 		calcLightsBufferSize(), bufferBits);
 		calcLightsBufferSize(), bufferBits);
+	if(err) return err;
 
 
-	m_tilesBuff.create(cmdBuff, GL_SHADER_STORAGE_BUFFER,
+	err = m_tilesBuff.create(cmdBuff, GL_SHADER_STORAGE_BUFFER,
 		m_r->getTilesCount().x() * m_r->getTilesCount().y() * m_tileSize,
 		m_r->getTilesCount().x() * m_r->getTilesCount().y() * m_tileSize,
 		bufferBits);
 		bufferBits);
+	if(err) return err;
 
 
 	// Last thing to do
 	// Last thing to do
 	cmdBuff.flush();
 	cmdBuff.flush();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::lightPass(GlCommandBufferHandle& cmdBuff)
+Error Is::lightPass(GlCommandBufferHandle& cmdBuff)
 {
 {
+	Error err = ErrorCode::NONE;
 	Threadpool& threadPool = m_r->_getThreadpool();
 	Threadpool& threadPool = m_r->_getThreadpool();
 	m_cam = &m_r->getSceneGraph().getActiveCamera();
 	m_cam = &m_r->getSceneGraph().getActiveCamera();
 	VisibilityTestResults& vi = m_cam->getVisibilityTestResults();
 	VisibilityTestResults& vi = m_cam->getVisibilityTestResults();
@@ -523,9 +549,11 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 	U visibleSpotTexLightsCount = 0;
 	U visibleSpotTexLightsCount = 0;
 	Array<Light*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
 	Array<Light*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
 
 
-	for(auto& it : vi.m_lights)
+	auto it = vi.getLightsBegin();
+	auto lend = vi.getLightsEnd();
+	for(; it != lend; ++it)
 	{
 	{
-		Light* light = staticCastPtr<Light*>(it.m_node);
+		Light* light = staticCastPtr<Light*>((*it).m_node);
 		switch(light->getLightType())
 		switch(light->getLightType())
 		{
 		{
 		case Light::Type::POINT:
 		case Light::Type::POINT:
@@ -564,7 +592,8 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 	//
 	//
 	// Do shadows pass
 	// Do shadows pass
 	//
 	//
-	m_sm.run(&shadowCasters[0], visibleSpotTexLightsCount, cmdBuff);
+	err = m_sm.run(&shadowCasters[0], visibleSpotTexLightsCount, cmdBuff);
+	if(err) return err;
 
 
 	//
 	//
 	// Write the lights and tiles UBOs
 	// Write the lights and tiles UBOs
@@ -594,12 +623,14 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 	GlClientBufferHandle lightsClientBuff;
 	GlClientBufferHandle lightsClientBuff;
 	if(totalLightsCount > 0)
 	if(totalLightsCount > 0)
 	{
 	{
-		lightsClientBuff.create(
+		err = lightsClientBuff.create(
 			cmdBuff, spotTexLightsOffset + spotTexLightsSize, nullptr);
 			cmdBuff, spotTexLightsOffset + spotTexLightsSize, nullptr);
+		if(err) return err;
 	}
 	}
 
 
 	GlClientBufferHandle tilesClientBuff;
 	GlClientBufferHandle tilesClientBuff;
-	tilesClientBuff.create(cmdBuff, m_tilesBuff.getSize(), nullptr);
+	err = tilesClientBuff.create(cmdBuff, m_tilesBuff.getSize(), nullptr);
+	if(err) return err;
 
 
 	AtomicU32 pointLightsAtomicCount(0);
 	AtomicU32 pointLightsAtomicCount(0);
 	AtomicU32 spotLightsAtomicCount(0);
 	AtomicU32 spotLightsAtomicCount(0);
@@ -643,8 +674,8 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 
 
 			job.m_tileBuffer = (U8*)tilesClientBuff.getBaseAddress();
 			job.m_tileBuffer = (U8*)tilesClientBuff.getBaseAddress();
 
 
-			job.m_lightsBegin = vi.m_lights.begin();
-			job.m_lightsEnd = vi.m_lights.end();
+			job.m_lightsBegin = vi.getLightsBegin();
+			job.m_lightsEnd = vi.getLightsEnd();
 
 
 			job.m_pointLightsCount = &pointLightsAtomicCount;
 			job.m_pointLightsCount = &pointLightsAtomicCount;
 			job.m_spotLightsCount = &spotLightsAtomicCount;
 			job.m_spotLightsCount = &spotLightsAtomicCount;
@@ -671,7 +702,8 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 	setState(cmdBuff);
 	setState(cmdBuff);
 
 
 	// Sync
 	// Sync
-	threadPool.waitForAllThreadsToFinish();
+	err = threadPool.waitForAllThreadsToFinish();
+	if(err) return err;
 
 
 	// Write the light count for each tile
 	// Write the light count for each tile
 	for(U y = 0; y < m_r->getTilesCount().y(); y++)
 	for(U y = 0; y < m_r->getTilesCount().y(); y++)
@@ -703,15 +735,16 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 		m_lightsBuff.write(cmdBuff,
 		m_lightsBuff.write(cmdBuff,
 			lightsClientBuff, 0, 0, spotTexLightsOffset + spotTexLightsSize);
 			lightsClientBuff, 0, 0, spotTexLightsOffset + spotTexLightsSize);
 	}
 	}
-	m_tilesBuff.write(cmdBuff, tilesClientBuff, 0, 0, tilesClientBuff.getSize());
+	m_tilesBuff.write(cmdBuff, tilesClientBuff, 0, 0, 
+		tilesClientBuff.getSize());
 
 
 	//
 	//
 	// Setup uniforms
 	// Setup uniforms
 	//
 	//
 
 
 	// shader prog
 	// shader prog
-
-	updateCommonBlock(cmdBuff);
+	err = updateCommonBlock(cmdBuff);
+	if(err) return err;
 
 
 	m_commonBuff.bindShaderBuffer(cmdBuff, COMMON_UNIFORMS_BLOCK_BINDING);
 	m_commonBuff.bindShaderBuffer(cmdBuff, COMMON_UNIFORMS_BLOCK_BINDING);
 
 
@@ -756,6 +789,8 @@ void Is::lightPass(GlCommandBufferHandle& cmdBuff)
 
 
 	cmdBuff.drawArrays(GL_TRIANGLE_STRIP, 4, 
 	cmdBuff.drawArrays(GL_TRIANGLE_STRIP, 4, 
 		m_r->getTilesCount().x() * m_r->getTilesCount().y());
 		m_r->getTilesCount().x() * m_r->getTilesCount().y());
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -780,19 +815,21 @@ void Is::setState(GlCommandBufferHandle& cmdBuff)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::run(GlCommandBufferHandle& cmdBuff)
+Error Is::run(GlCommandBufferHandle& cmdBuff)
 {
 {
 	// Do the light pass including the shadow passes
 	// Do the light pass including the shadow passes
-	lightPass(cmdBuff);
+	return lightPass(cmdBuff);
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::updateCommonBlock(GlCommandBufferHandle& cmdBuff)
+Error Is::updateCommonBlock(GlCommandBufferHandle& cmdBuff)
 {
 {
 	SceneGraph& scene = m_r->getSceneGraph();
 	SceneGraph& scene = m_r->getSceneGraph();
 
 
 	GlClientBufferHandle cbuff;
 	GlClientBufferHandle cbuff;
-	cbuff.create(cmdBuff, sizeof(shader::CommonUniforms), nullptr);
+	Error err = cbuff.create(cmdBuff, sizeof(shader::CommonUniforms), nullptr);
+	if(err) return err;
+
 	shader::CommonUniforms& blk = 
 	shader::CommonUniforms& blk = 
 		*(shader::CommonUniforms*)cbuff.getBaseAddress();
 		*(shader::CommonUniforms*)cbuff.getBaseAddress();
 
 
@@ -809,6 +846,8 @@ void Is::updateCommonBlock(GlCommandBufferHandle& cmdBuff)
 	}
 	}
 
 
 	m_commonBuff.write(cmdBuff, cbuff, 0, 0, cbuff.getSize());
 	m_commonBuff.write(cmdBuff, cbuff, 0, 0, cbuff.getSize());
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 95 - 36
src/renderer/Lf.cpp

@@ -55,92 +55,120 @@ Lf::~Lf()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Lf::init(const ConfigSet& config)
+Error Lf::init(const ConfigSet& config)
 {
 {
-	try
+	Error err = initInternal(config);
+	if(err)
 	{
 	{
-		initInternal(config);
-	}
-	catch(const std::exception& e)
-	{
-		throw ANKI_EXCEPTION("Failed to init lens flare pass") << e;
+		ANKI_LOGE("Failed to init lens flare pass");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Lf::initInternal(const ConfigSet& config)
+Error Lf::initInternal(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
 	m_enabled = config.get("pps.lf.enabled") 
 	m_enabled = config.get("pps.lf.enabled") 
 		&& config.get("pps.hdr.enabled");
 		&& config.get("pps.hdr.enabled");
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return err;
 	}
 	}
 
 
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
 
 
 	m_maxFlaresPerLight = config.get("pps.lf.maxFlaresPerLight");
 	m_maxFlaresPerLight = config.get("pps.lf.maxFlaresPerLight");
 	m_maxLightsWithFlares = config.get("pps.lf.maxLightsWithFlares");
 	m_maxLightsWithFlares = config.get("pps.lf.maxLightsWithFlares");
 
 
 	// Load program 1
 	// Load program 1
-	String pps(getAllocator());
-	pps.sprintf("#define TEX_DIMENSIONS vec2(%u.0, %u.0)\n", 
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
+
+	err = pps.sprintf(getAllocator(), 
+		"#define TEX_DIMENSIONS vec2(%u.0, %u.0)\n", 
 		m_r->getPps().getHdr()._getWidth(),
 		m_r->getPps().getHdr()._getWidth(),
 		m_r->getPps().getHdr()._getHeight());
 		m_r->getPps().getHdr()._getHeight());
+	if(err) return err;
 
 
-	m_pseudoFrag.loadToCache(&getResourceManager(), 
+	err = m_pseudoFrag.loadToCache(&getResourceManager(), 
 		"shaders/PpsLfPseudoPass.frag.glsl", pps.toCString(), "r_");
 		"shaders/PpsLfPseudoPass.frag.glsl", pps.toCString(), "r_");
-	m_pseudoPpline = m_r->createDrawQuadProgramPipeline(
-		m_pseudoFrag->getGlProgram());
+	if(err) return err;
+
+	err = m_r->createDrawQuadProgramPipeline(
+		m_pseudoFrag->getGlProgram(), m_pseudoPpline);
+	if(err) return err;
 
 
 	// Load program 2
 	// Load program 2
-	pps.sprintf("#define MAX_FLARES %u\n",
+	pps.destroy(getAllocator());
+	err = pps.sprintf(getAllocator(), "#define MAX_FLARES %u\n",
 		m_maxFlaresPerLight * m_maxLightsWithFlares);
 		m_maxFlaresPerLight * m_maxLightsWithFlares);
+	if(err)
+	{
+		return err;
+	}
 
 
-	m_realVert.loadToCache(&getResourceManager(), 
+	err = m_realVert.loadToCache(&getResourceManager(), 
 		"shaders/PpsLfSpritePass.vert.glsl", pps.toCString(), "r_");
 		"shaders/PpsLfSpritePass.vert.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_realFrag.loadToCache(&getResourceManager(), 
+	err = m_realFrag.loadToCache(&getResourceManager(), 
 		"shaders/PpsLfSpritePass.frag.glsl", pps.toCString(), "r_");
 		"shaders/PpsLfSpritePass.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_realPpline.create(cmdBuff,
+	err = m_realPpline.create(cmdBuff,
 		{m_realVert->getGlProgram(), m_realFrag->getGlProgram()});
 		{m_realVert->getGlProgram(), m_realFrag->getGlProgram()});
+	if(err) return err;
 
 
 	PtrSize blockSize = 
 	PtrSize blockSize = 
 		sizeof(Flare) * m_maxFlaresPerLight * m_maxLightsWithFlares;
 		sizeof(Flare) * m_maxFlaresPerLight * m_maxLightsWithFlares;
 	if(m_realVert->getGlProgram().tryFindBlock("bFlares")->getSize() 
 	if(m_realVert->getGlProgram().tryFindBlock("bFlares")->getSize() 
 		!= blockSize)
 		!= blockSize)
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect block size");
+		ANKI_LOGE("Incorrect block size");
+		return ErrorCode::FUNCTION_FAILED;
 	}
 	}
 
 
 	// Init buffer
 	// Init buffer
-	m_flareDataBuff.create(
+	err = m_flareDataBuff.create(
 		cmdBuff, GL_UNIFORM_BUFFER, blockSize, GL_DYNAMIC_STORAGE_BIT);
 		cmdBuff, GL_UNIFORM_BUFFER, blockSize, GL_DYNAMIC_STORAGE_BIT);
+	if(err) return err;
 
 
 	// Create the render target
 	// Create the render target
-	m_r->createRenderTarget(m_r->getPps().getHdr()._getWidth(), 
+	err = m_r->createRenderTarget(m_r->getPps().getHdr()._getWidth(), 
 		m_r->getPps().getHdr()._getHeight(), 
 		m_r->getPps().getHdr()._getHeight(), 
 		GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt);
 		GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt);
+	if(err) return err;
 
 
-	m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}}); 
+	err = m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
 	
 	
 	// Textures
 	// Textures
-	m_lensDirtTex.load("engine_data/lens_dirt.ankitex", &getResourceManager());
+	err = m_lensDirtTex.load(
+		"engine_data/lens_dirt.ankitex", &getResourceManager());
+	if(err) return err;
 
 
 	// Blit
 	// Blit
-	m_blitFrag.load("shaders/Blit.frag.glsl", &getResourceManager());
-	m_blitPpline = m_r->createDrawQuadProgramPipeline(
-		m_blitFrag->getGlProgram());
+	err = m_blitFrag.load("shaders/Blit.frag.glsl", &getResourceManager());
+	if(err) return err;
+
+	err = m_r->createDrawQuadProgramPipeline(
+		m_blitFrag->getGlProgram(), m_blitPpline);
+	if(err) return err;
 
 
 	cmdBuff.finish();
 	cmdBuff.finish();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Lf::run(GlCommandBufferHandle& cmdBuff)
+Error Lf::run(GlCommandBufferHandle& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	//
 	//
 	// First pass
 	// First pass
@@ -170,13 +198,22 @@ void Lf::run(GlCommandBufferHandle& cmdBuff)
 	VisibilityTestResults& vi = cam.getVisibilityTestResults();
 	VisibilityTestResults& vi = cam.getVisibilityTestResults();
 
 
 	// Iterate the visible light and get those that have lens flare
 	// Iterate the visible light and get those that have lens flare
-	SceneFrameVector<Light*> lights(
-		m_maxLightsWithFlares, nullptr, scene.getFrameAllocator());
+	SceneDArray<Light*> lights;
+	SceneDArray<Light*>::ScopeDestroyer lightsd(
+		&lights, scene.getFrameAllocator());
+	err = lights.create(
+		scene.getFrameAllocator(), m_maxLightsWithFlares, nullptr);
+	if(err)
+	{
+		return err;
+	}
 
 
 	U lightsCount = 0;
 	U lightsCount = 0;
-	for(auto& it : vi.m_lights)
+	auto it = vi.getLightsBegin();
+	auto end = vi.getLightsEnd();
+	for(; it != end; ++it)
 	{
 	{
-		SceneNode& sn = *it.m_node;
+		SceneNode& sn = *(it->m_node);
 		ANKI_ASSERT(sn.tryGetComponent<LightComponent>() != nullptr);
 		ANKI_ASSERT(sn.tryGetComponent<LightComponent>() != nullptr);
 		Light* light = staticCastPtr<Light*>(&sn);
 		Light* light = staticCastPtr<Light*>(&sn);
 
 
@@ -201,15 +238,35 @@ void Lf::run(GlCommandBufferHandle& cmdBuff)
 		// Write the UBO and get the groups
 		// Write the UBO and get the groups
 		//
 		//
 		GlClientBufferHandle flaresCBuff;
 		GlClientBufferHandle flaresCBuff;
-		flaresCBuff.create(cmdBuff,
+		err = flaresCBuff.create(cmdBuff,
 			sizeof(Flare) * lightsCount * m_maxFlaresPerLight, nullptr);
 			sizeof(Flare) * lightsCount * m_maxFlaresPerLight, nullptr);
+		if(err)
+		{
+			return err;
+		}
+
 		Flare* flares = (Flare*)flaresCBuff.getBaseAddress();
 		Flare* flares = (Flare*)flaresCBuff.getBaseAddress();
 		U flaresCount = 0;
 		U flaresCount = 0;
 
 
 		// Contains the number of flares per flare texture
 		// Contains the number of flares per flare texture
-		SceneFrameVector<U> groups(lightsCount, 0U, scene.getFrameAllocator());
-		SceneFrameVector<const GlTextureHandle*> texes(
-			lightsCount, nullptr, scene.getFrameAllocator());
+		SceneFrameDArray<U> groups;
+		SceneFrameDArray<U>::ScopeDestroyer groupsd(
+			&groups, scene.getFrameAllocator());
+		err = groups.create(scene.getFrameAllocator(), lightsCount, 0U);
+		if(err)
+		{
+			return err;
+		}
+
+		SceneFrameDArray<const GlTextureHandle*> texes;
+		SceneFrameDArray<const GlTextureHandle*>::ScopeDestroyer 
+			texesd(&texes, scene.getFrameAllocator());
+		err = texes.create(scene.getFrameAllocator(), lightsCount, nullptr);
+		if(err)
+		{
+			return err;
+		}
+
 		U groupsCount = 0;
 		U groupsCount = 0;
 
 
 		GlTextureHandle lastTex;
 		GlTextureHandle lastTex;
@@ -331,6 +388,8 @@ void Lf::run(GlCommandBufferHandle& cmdBuff)
 	m_r->drawQuad(cmdBuff);
 	m_r->drawQuad(cmdBuff);
 
 
 	cmdBuff.enableBlend(false);
 	cmdBuff.enableBlend(false);
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 41 - 24
src/renderer/MainRenderer.cpp

@@ -15,24 +15,22 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-MainRenderer::MainRenderer(
-	Threadpool* threadpool, 
-	ResourceManager* resources,
-	GlDevice* gl,
-	HeapAllocator<U8>& alloc,
-	const ConfigSet& config)
-:	Renderer(threadpool, resources, gl, alloc, config)
-{
-	init(config);
-}
+MainRenderer::MainRenderer()	
+{}
 
 
 //==============================================================================
 //==============================================================================
 MainRenderer::~MainRenderer()
 MainRenderer::~MainRenderer()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void MainRenderer::init(const ConfigSet& config_)
+Error MainRenderer::init(
+	Threadpool* threadpool, 
+	ResourceManager* resources,
+	GlDevice* gl,
+	HeapAllocator<U8>& alloc,
+	const ConfigSet& config_)
 {
 {
+	Error err = ErrorCode::NONE;
 	ANKI_LOGI("Initializing main renderer...");
 	ANKI_LOGI("Initializing main renderer...");
 
 
 	ConfigSet config = config_;
 	ConfigSet config = config_;
@@ -42,21 +40,29 @@ void MainRenderer::init(const ConfigSet& config_)
 	config.set("height", 
 	config.set("height", 
 		config.get("height") * config.get("renderingQuality"));
 		config.get("height") * config.get("renderingQuality"));
 
 
-	initGl();
+	err = initGl();
+	if(err) return err;
+
+	err = Renderer::init(threadpool, resources, gl, alloc, config);
+	if(err) return err;
 
 
-	Renderer::init(config);
+	err = m_blitFrag.load("shaders/Final.frag.glsl", &_getResourceManager());
+	if(err) return err;
 
 
-	m_blitFrag.load("shaders/Final.frag.glsl", &_getResourceManager());
-	m_blitPpline = createDrawQuadProgramPipeline(
-		m_blitFrag->getGlProgram());
+	err = createDrawQuadProgramPipeline(
+		m_blitFrag->getGlProgram(), m_blitPpline);
+	if(err) return err;
 
 
 	ANKI_LOGI("Main renderer initialized. Rendering size %dx%d", 
 	ANKI_LOGI("Main renderer initialized. Rendering size %dx%d", 
 		getWidth(), getHeight());
 		getWidth(), getHeight());
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void MainRenderer::render(SceneGraph& scene)
+Error MainRenderer::render(SceneGraph& scene)
 {
 {
+	Error err = ErrorCode::NONE;
 	ANKI_COUNTER_START_TIMER(MAIN_RENDERER_TIME);
 	ANKI_COUNTER_START_TIMER(MAIN_RENDERER_TIME);
 
 
 	GlDevice& gl = _getGlDevice();
 	GlDevice& gl = _getGlDevice();
@@ -65,10 +71,12 @@ void MainRenderer::render(SceneGraph& scene)
 
 
 	for(U i = 0; i < JOB_CHAINS_COUNT; i++)
 	for(U i = 0; i < JOB_CHAINS_COUNT; i++)
 	{
 	{
-		jobs[i].create(&gl, m_jobsInitHints[i]);
+		err = jobs[i].create(&gl, m_jobsInitHints[i]);
+		if(err) return err;
 	}
 	}
 
 
-	Renderer::render(scene, jobs);
+	err = Renderer::render(scene, jobs);
+	if(err) return err;
 
 
 	Bool notDrawnToDefault = 
 	Bool notDrawnToDefault = 
 		getRenderingQuality() != 1.0 || getDbg().getEnabled();
 		getRenderingQuality() != 1.0 || getDbg().getEnabled();
@@ -111,20 +119,27 @@ void MainRenderer::render(SceneGraph& scene)
 	lastJobs.flush();
 	lastJobs.flush();
 
 
 	ANKI_COUNTER_STOP_TIMER_INC(MAIN_RENDERER_TIME);
 	ANKI_COUNTER_STOP_TIMER_INC(MAIN_RENDERER_TIME);
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void MainRenderer::initGl()
+Error MainRenderer::initGl()
 {
 {
 	// get max texture units
 	// get max texture units
 	GlDevice& gl = _getGlDevice();
 	GlDevice& gl = _getGlDevice();
 	GlCommandBufferHandle jobs;
 	GlCommandBufferHandle jobs;
-	jobs.create(&gl);
+	Error err = jobs.create(&gl);
 
 
-	jobs.enableCulling(true);
-	jobs.setCullFace(GL_BACK);
+	if(!err)
+	{
+		jobs.enableCulling(true);
+		jobs.setCullFace(GL_BACK);
 
 
-	jobs.flush();
+		jobs.flush();
+	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -190,6 +205,7 @@ void MainRenderer::takeScreenshotTga(const char* filename)
 //==============================================================================
 //==============================================================================
 void MainRenderer::takeScreenshot(const char* filename)
 void MainRenderer::takeScreenshot(const char* filename)
 {
 {
+#if 0
 	String ext = getFileExtension(filename, _getAllocator());
 	String ext = getFileExtension(filename, _getAllocator());
 
 
 	// exec from this extension
 	// exec from this extension
@@ -202,6 +218,7 @@ void MainRenderer::takeScreenshot(const char* filename)
 		throw ANKI_EXCEPTION("Unsupported file extension");
 		throw ANKI_EXCEPTION("Unsupported file extension");
 	}
 	}
 	ANKI_LOGI("Screenshot %s saved", filename);
 	ANKI_LOGI("Screenshot %s saved", filename);
+#endif
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 78 - 47
src/renderer/Ms.cpp

@@ -19,80 +19,104 @@ Ms::~Ms()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Ms::createRt(U32 index, U32 samples)
+Error Ms::createRt(U32 index, U32 samples)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	Plane& plane = m_planes[index];
 	Plane& plane = m_planes[index];
 
 
-	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
+	err = m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
 		GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
 		GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
 		GL_UNSIGNED_INT, samples, plane.m_depthRt);
 		GL_UNSIGNED_INT, samples, plane.m_depthRt);
+	if(err) return err;
 
 
-	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGBA8,
+	err = m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGBA8,
 			GL_RGBA, GL_UNSIGNED_BYTE, samples, plane.m_rt0);
 			GL_RGBA, GL_UNSIGNED_BYTE, samples, plane.m_rt0);
+	if(err) return err;
 
 
-	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGBA8,
+	err = m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGBA8,
 		GL_RGBA, GL_UNSIGNED_BYTE, samples, plane.m_rt1);
 		GL_RGBA, GL_UNSIGNED_BYTE, samples, plane.m_rt1);
+	if(err) return err;
 
 
 	GlDevice& gl = getGlDevice();
 	GlDevice& gl = getGlDevice();
 	GlCommandBufferHandle cmdb;
 	GlCommandBufferHandle cmdb;
-	cmdb.create(&gl);
+	err = cmdb.create(&gl);
+	if(err)	return err;
 
 
-	plane.m_fb.create(
+	err = plane.m_fb.create(
 		cmdb,
 		cmdb,
 		{{plane.m_rt0, GL_COLOR_ATTACHMENT0}, 
 		{{plane.m_rt0, GL_COLOR_ATTACHMENT0}, 
 		{plane.m_rt1, GL_COLOR_ATTACHMENT1},
 		{plane.m_rt1, GL_COLOR_ATTACHMENT1},
 		{plane.m_depthRt, GL_DEPTH_ATTACHMENT}});
 		{plane.m_depthRt, GL_DEPTH_ATTACHMENT}});
+	if(err)	return err;
 
 
 	cmdb.finish();
 	cmdb.finish();
+
+	return err;
+}
+
+//==============================================================================
+Error Ms::init(const ConfigSet& initializer)
+{
+	Error err = initInternal(initializer);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize material stage");
+	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ms::init(const ConfigSet& initializer)
+Error Ms::initInternal(const ConfigSet& initializer)
 {
 {
-	try
+	Error err = ErrorCode::NONE;
+
+	if(initializer.get("samples") > 1)
 	{
 	{
-		if(initializer.get("samples") > 1)
-		{
-			createRt(0, initializer.get("samples"));
-		}
-		createRt(1, 1);
-
-		// Init small depth 
-		{
-			m_smallDepthSize = UVec2(
-				getAlignedRoundDown(16, m_r->getWidth() / 3),
-				getAlignedRoundDown(16, m_r->getHeight() / 3));
-
-			m_r->createRenderTarget(
-				m_smallDepthSize.x(), 
-				m_smallDepthSize.y(),
-				GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
-				GL_UNSIGNED_INT, 1, m_smallDepthRt);
-
-			GlDevice& gl = getGlDevice();
-			GlCommandBufferHandle cmdb;
-			cmdb.create(&gl);
-
-			m_smallDepthRt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
-
-			m_smallDepthFb.create(
-				cmdb,
-				{{m_smallDepthRt, GL_DEPTH_ATTACHMENT}});
-
-			cmdb.finish();
-		}
-
-		m_ez.init(initializer);
+		err = createRt(0, initializer.get("samples"));
+		if(err)	return err;
 	}
 	}
-	catch(const std::exception& e)
+	err = createRt(1, 1);
+	if(err)	return err;
+
+	// Init small depth 
 	{
 	{
-		throw ANKI_EXCEPTION("Failed to initialize material stage") << e;
+		m_smallDepthSize = UVec2(
+			getAlignedRoundDown(16, m_r->getWidth() / 3),
+			getAlignedRoundDown(16, m_r->getHeight() / 3));
+
+		err = m_r->createRenderTarget(
+			m_smallDepthSize.x(), 
+			m_smallDepthSize.y(),
+			GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
+			GL_UNSIGNED_INT, 1, m_smallDepthRt);
+		if(err) return err;
+
+		GlDevice& gl = getGlDevice();
+		GlCommandBufferHandle cmdb;
+		err = cmdb.create(&gl);
+		if(err)	return err;
+
+		m_smallDepthRt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
+
+		err = m_smallDepthFb.create(
+			cmdb,
+			{{m_smallDepthRt, GL_DEPTH_ATTACHMENT}});
+		if(err)	return err;
+
+		cmdb.finish();
 	}
 	}
+
+	err = m_ez.init(initializer);
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ms::run(GlCommandBufferHandle& cmdb)
+Error Ms::run(GlCommandBufferHandle& cmdb)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	// Chose the multisampled or the singlesampled framebuffer
 	// Chose the multisampled or the singlesampled framebuffer
 	if(m_r->getSamples() > 1)
 	if(m_r->getSamples() > 1)
 	{
 	{
@@ -118,7 +142,8 @@ void Ms::run(GlCommandBufferHandle& cmdb)
 		cmdb.setDepthFunction(GL_LESS);
 		cmdb.setDepthFunction(GL_LESS);
 		cmdb.setColorWriteMask(false, false, false, false);
 		cmdb.setColorWriteMask(false, false, false, false);
 
 
-		m_ez.run(cmdb);
+		err = m_ez.run(cmdb);
+		if(err) return err;
 
 
 		cmdb.setDepthFunction(GL_LEQUAL);
 		cmdb.setDepthFunction(GL_LEQUAL);
 		cmdb.setColorWriteMask(true, true, true, true);
 		cmdb.setColorWriteMask(true, true, true, true);
@@ -128,13 +153,17 @@ void Ms::run(GlCommandBufferHandle& cmdb)
 	m_r->getSceneDrawer().prepareDraw(RenderingStage::MATERIAL, Pass::COLOR,
 	m_r->getSceneDrawer().prepareDraw(RenderingStage::MATERIAL, Pass::COLOR,
 		cmdb);
 		cmdb);
 
 
+	Camera& cam = m_r->getSceneGraph().getActiveCamera();
+	
 	VisibilityTestResults& vi =
 	VisibilityTestResults& vi =
 		m_r->getSceneGraph().getActiveCamera().getVisibilityTestResults();
 		m_r->getSceneGraph().getActiveCamera().getVisibilityTestResults();
 
 
-	Camera& cam = m_r->getSceneGraph().getActiveCamera();
-	for(auto& it : vi.m_renderables)
+	auto it = vi.getRenderablesBegin();
+	auto end = vi.getRenderablesEnd();
+	for(; it != end; ++it)
 	{
 	{
-		m_r->getSceneDrawer().render(cam, it);
+		err = m_r->getSceneDrawer().render(cam, *it);
+		if(err) return err;
 	}
 	}
 
 
 	m_r->getSceneDrawer().finishDraw();
 	m_r->getSceneDrawer().finishDraw();
@@ -158,6 +187,8 @@ void Ms::run(GlCommandBufferHandle& cmdb)
 		GL_DEPTH_BUFFER_BIT, false);
 		GL_DEPTH_BUFFER_BIT, false);
 
 
 	cmdb.enableDepthTest(false);
 	cmdb.enableDepthTest(false);
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 49 - 27
src/renderer/Pps.cpp

@@ -27,34 +27,44 @@ Pps::~Pps()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void Pps::initInternal(const ConfigSet& config)
+Error Pps::initInternal(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_enabled = config.get("pps.enabled");
 	m_enabled = config.get("pps.enabled");
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return err;
 	}
 	}
 
 
 	ANKI_ASSERT("Initializing PPS");
 	ANKI_ASSERT("Initializing PPS");
 
 
-	m_ssao.init(config);
-	m_hdr.init(config);
-	m_lf.init(config);
-	m_sslr.init(config);
+	err = m_ssao.init(config);
+	if(err) return err;
+	err = m_hdr.init(config);
+	if(err) return err;
+	err = m_lf.init(config);
+	if(err) return err;
+	err = m_sslr.init(config);
+	if(err) return err;
 
 
 	// FBO
 	// FBO
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
 
 
-	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGB8, GL_RGB,
-		GL_UNSIGNED_BYTE, 1, m_rt);
+	err = m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGB8, 
+		GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt);
+	if(err) return err;
 
 
-	m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	err = m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
 
 
 	// SProg
 	// SProg
-	String pps(getAllocator());
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
 
 
-	pps.sprintf(
+	err = pps.sprintf(getAllocator(),
 		"#define SSAO_ENABLED %u\n"
 		"#define SSAO_ENABLED %u\n"
 		"#define HDR_ENABLED %u\n"
 		"#define HDR_ENABLED %u\n"
 		"#define SHARPEN_ENABLED %u\n"
 		"#define SHARPEN_ENABLED %u\n"
@@ -67,53 +77,62 @@ void Pps::initInternal(const ConfigSet& config)
 		static_cast<U>(config.get("pps.gammaCorrection")),
 		static_cast<U>(config.get("pps.gammaCorrection")),
 		m_r->getWidth(),
 		m_r->getWidth(),
 		m_r->getHeight());
 		m_r->getHeight());
+	if(err) return err;
 
 
-	m_frag.loadToCache(&getResourceManager(),
+	err = m_frag.loadToCache(&getResourceManager(),
 		"shaders/Pps.frag.glsl", pps.toCString(), "r_");
 		"shaders/Pps.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_ppline = m_r->createDrawQuadProgramPipeline(m_frag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(m_frag->getGlProgram(), m_ppline);
+	if(err) return err;
 
 
 	cmdBuff.finish();
 	cmdBuff.finish();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Pps::init(const ConfigSet& config)
+Error Pps::init(const ConfigSet& config)
 {
 {
-	try
-	{
-		initInternal(config);
-	}
-	catch(const std::exception& e)
+	Error err = initInternal(config);
+	if(err)
 	{
 	{
-		throw ANKI_EXCEPTION("Failed to init PPS") << e;
+		ANKI_LOGE("Failed to init PPS");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Pps::run(GlCommandBufferHandle& cmdBuff)
+Error Pps::run(GlCommandBufferHandle& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	// First SSAO because it depends on MS where HDR depends on IS
 	// First SSAO because it depends on MS where HDR depends on IS
 	if(m_ssao.getEnabled())
 	if(m_ssao.getEnabled())
 	{
 	{
-		m_ssao.run(cmdBuff);
+		err = m_ssao.run(cmdBuff);
+		if(err) return err;
 	}
 	}
 
 
 	// Then SSLR because HDR depends on it
 	// Then SSLR because HDR depends on it
 	if(m_sslr.getEnabled())
 	if(m_sslr.getEnabled())
 	{
 	{
-		m_sslr.run(cmdBuff);
+		err = m_sslr.run(cmdBuff);
+		if(err) return err;
 	}
 	}
 
 
 	if(m_hdr.getEnabled())
 	if(m_hdr.getEnabled())
 	{
 	{
-		m_hdr.run(cmdBuff);
+		err = m_hdr.run(cmdBuff);
+		if(err) return err;
 	}
 	}
 
 
 	if(m_lf.getEnabled())
 	if(m_lf.getEnabled())
 	{
 	{
-		m_lf.run(cmdBuff);
+		err = m_lf.run(cmdBuff);
+		if(err) return err;
 	}
 	}
 
 
 	Bool drawToDefaultFbo = 
 	Bool drawToDefaultFbo = 
@@ -124,7 +143,8 @@ void Pps::run(GlCommandBufferHandle& cmdBuff)
 	if(drawToDefaultFbo)
 	if(drawToDefaultFbo)
 	{
 	{
 		m_r->getDefaultFramebuffer().bind(cmdBuff, true);
 		m_r->getDefaultFramebuffer().bind(cmdBuff, true);
-		cmdBuff.setViewport(0, 0, m_r->getWindowWidth(), m_r->getWindowHeight());
+		cmdBuff.setViewport(
+			0, 0, m_r->getWindowWidth(), m_r->getWindowHeight());
 	}
 	}
 	else
 	else
 	{
 	{
@@ -151,6 +171,8 @@ void Pps::run(GlCommandBufferHandle& cmdBuff)
 	}
 	}
 
 
 	m_r->drawQuad(cmdBuff);
 	m_r->drawQuad(cmdBuff);
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 107 - 49
src/renderer/Renderer.cpp

@@ -13,33 +13,48 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-Renderer::Renderer(
-	Threadpool* threadpool, 
-	ResourceManager* resources,
-	GlDevice* gl,
-	HeapAllocator<U8>& alloc,
-	const ConfigSet& config)
-:	m_threadpool(threadpool),
-	m_resources(resources),
-	m_gl(gl),
-	m_alloc(alloc),
-	m_ms(this), 
+Renderer::Renderer()
+:	m_ms(this), 
 	m_is(this),
 	m_is(this),
 	m_pps(this),
 	m_pps(this),
 	m_bs(this),
 	m_bs(this),
 	m_dbg(this), 
 	m_dbg(this), 
-	m_tiler(this),
-	m_sceneDrawer(this),
-	m_shadersPrependedSource(alloc)
+	m_tiler(this)
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
 Renderer::~Renderer()
 Renderer::~Renderer()
-{}
+{
+	m_shadersPrependedSource.destroy(m_alloc);
+}
+
+//==============================================================================
+Error Renderer::init(
+	Threadpool* threadpool, 
+	ResourceManager* resources,
+	GlDevice* gl,
+	HeapAllocator<U8>& alloc,
+	const ConfigSet& config)
+{
+	m_threadpool = threadpool;
+	m_resources = resources;
+	m_gl = gl;
+	m_alloc = alloc;
+
+	Error err = initInternal(config);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize the renderer");
+	}
+
+	return err;
+}
 
 
 //==============================================================================
 //==============================================================================
-void Renderer::init(const ConfigSet& config)
+Error Renderer::initInternal(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	// Set from the config
 	// Set from the config
 	m_width = config.get("width");
 	m_width = config.get("width");
 	m_height = config.get("height");
 	m_height = config.get("height");
@@ -57,54 +72,75 @@ void Renderer::init(const ConfigSet& config)
 	if(m_samples != 1 && m_samples != 4 && m_samples != 8 && m_samples != 16
 	if(m_samples != 1 && m_samples != 4 && m_samples != 8 && m_samples != 16
 		&& m_samples != 32)
 		&& m_samples != 32)
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect samples");
+		ANKI_LOGE("Incorrect samples");
+		return ErrorCode::USER_DATA;
 	}
 	}
 
 
 	if(m_width < 10 || m_height < 10)
 	if(m_width < 10 || m_height < 10)
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect sizes");
+		ANKI_LOGE("Incorrect sizes");
+		return ErrorCode::USER_DATA;
 	}
 	}
 
 
+	// Drawer
+	err = m_sceneDrawer.create(this);
+	if(err) return err;
+
 	// quad setup
 	// quad setup
 	static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {-1.0, 1.0}, 
 	static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {-1.0, 1.0}, 
 		{1.0, -1.0}, {-1.0, -1.0}};
 		{1.0, -1.0}, {-1.0, -1.0}};
 
 
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(m_gl);
+	err = cmdBuff.create(m_gl);
+	if(err) return err;
 
 
 	GlClientBufferHandle tmpBuff;
 	GlClientBufferHandle tmpBuff;
-	tmpBuff.create(
+	err = tmpBuff.create(
 		cmdBuff, sizeof(quadVertCoords), (void*)&quadVertCoords[0][0]);
 		cmdBuff, sizeof(quadVertCoords), (void*)&quadVertCoords[0][0]);
+	if(err) return err;
 
 
-	m_quadPositionsBuff.create(cmdBuff, GL_ARRAY_BUFFER, tmpBuff, 0);
+	err = m_quadPositionsBuff.create(cmdBuff, GL_ARRAY_BUFFER, tmpBuff, 0);
+	if(err) return err;
 
 
-	m_drawQuadVert.load("shaders/Quad.vert.glsl", m_resources);
+	err = m_drawQuadVert.load("shaders/Quad.vert.glsl", m_resources);
+	if(err) return err;
 
 
 	// Init the stages. Careful with the order!!!!!!!!!!
 	// Init the stages. Careful with the order!!!!!!!!!!
-	m_tiler.init();
-
-	m_ms.init(config);
-	m_is.init(config);
-	m_bs.init(config);
-	m_pps.init(config);
-	m_dbg.init(config);
+	err = m_tiler.init();
+	if(err) return err;
+
+	err = m_ms.init(config);
+	if(err) return err;
+	err = m_is.init(config);
+	if(err) return err;
+	err = m_bs.init(config);
+	if(err) return err;
+	err = m_pps.init(config);
+	if(err) return err;
+	err = m_dbg.init(config);
+	if(err) return err;
 
 
 	// Default FB
 	// Default FB
-	m_defaultFb.create(cmdBuff, {});
+	err = m_defaultFb.create(cmdBuff, {});
+	if(err) return err;
 
 
 	cmdBuff.finish();
 	cmdBuff.finish();
 
 
 	// Set the default preprocessor string
 	// Set the default preprocessor string
-	m_shadersPrependedSource.sprintf(
+	err = m_shadersPrependedSource.sprintf(
+		m_alloc,
 		"#define ANKI_RENDERER_WIDTH %u\n"
 		"#define ANKI_RENDERER_WIDTH %u\n"
 		"#define ANKI_RENDERER_HEIGHT %u\n",
 		"#define ANKI_RENDERER_HEIGHT %u\n",
 		m_width, m_height);
 		m_width, m_height);
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Renderer::render(SceneGraph& scene, 
+Error Renderer::render(SceneGraph& scene, 
 	Array<GlCommandBufferHandle, JOB_CHAINS_COUNT>& cmdBuff)
 	Array<GlCommandBufferHandle, JOB_CHAINS_COUNT>& cmdBuff)
 {
 {
+	Error err = ErrorCode::NONE;
 	m_scene = &scene;
 	m_scene = &scene;
 	Camera& cam = m_scene->getActiveCamera();
 	Camera& cam = m_scene->getActiveCamera();
 
 
@@ -122,7 +158,8 @@ void Renderer::render(SceneGraph& scene,
 	}
 	}
 
 
 	ANKI_COUNTER_START_TIMER(RENDERER_MS_TIME);
 	ANKI_COUNTER_START_TIMER(RENDERER_MS_TIME);
-	m_ms.run(cmdBuff[0]);
+	err = m_ms.run(cmdBuff[0]);
+	if(err) return err;
 	ANKI_ASSERT(cmdBuff[0].getReferenceCount() == 1);
 	ANKI_ASSERT(cmdBuff[0].getReferenceCount() == 1);
 	cmdBuff[0].flush();
 	cmdBuff[0].flush();
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_MS_TIME);
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_MS_TIME);
@@ -130,24 +167,30 @@ void Renderer::render(SceneGraph& scene,
 	m_tiler.runMinMax(m_ms._getDepthRt());
 	m_tiler.runMinMax(m_ms._getDepthRt());
 
 
 	ANKI_COUNTER_START_TIMER(RENDERER_IS_TIME);
 	ANKI_COUNTER_START_TIMER(RENDERER_IS_TIME);
-	m_is.run(cmdBuff[1]);
+	err = m_is.run(cmdBuff[1]);
+	if(err) return err;
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_IS_TIME);
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_IS_TIME);
 
 
-	m_bs.run(cmdBuff[1]);
+	err = m_bs.run(cmdBuff[1]);
+	if(err) return err;
 
 
 	ANKI_COUNTER_START_TIMER(RENDERER_PPS_TIME);
 	ANKI_COUNTER_START_TIMER(RENDERER_PPS_TIME);
 	if(m_pps.getEnabled())
 	if(m_pps.getEnabled())
 	{
 	{
-		m_pps.run(cmdBuff[1]);
+		err = m_pps.run(cmdBuff[1]);
+		if(err) return err;
 	}
 	}
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_PPS_TIME);
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_PPS_TIME);
 
 
 	if(m_dbg.getEnabled())
 	if(m_dbg.getEnabled())
 	{
 	{
-		m_dbg.run(cmdBuff[1]);
+		err = m_dbg.run(cmdBuff[1]);
+		if(err) return err;
 	}
 	}
 
 
 	++m_framesNum;
 	++m_framesNum;
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -204,9 +247,11 @@ void Renderer::computeProjectionParams(const Mat4& m)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Renderer::createRenderTarget(U32 w, U32 h, GLenum internalFormat, 
+Error Renderer::createRenderTarget(U32 w, U32 h, GLenum internalFormat, 
 	GLenum format, GLenum type, U32 samples, GlTextureHandle& rt)
 	GLenum format, GLenum type, U32 samples, GlTextureHandle& rt)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	// Not very important but keep the resulution of render targets aligned to
 	// Not very important but keep the resulution of render targets aligned to
 	// 16
 	// 16
 	if(0)
 	if(0)
@@ -237,25 +282,38 @@ void Renderer::createRenderTarget(U32 w, U32 h, GLenum internalFormat,
 	init.m_samples = samples;
 	init.m_samples = samples;
 
 
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(m_gl);
-	rt.create(cmdBuff, init);
-	cmdBuff.finish();
+	err = cmdBuff.create(m_gl);
+
+	if(!err)
+	{
+		rt.create(cmdBuff, init);
+		cmdBuff.finish();
+	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-GlProgramPipelineHandle Renderer::createDrawQuadProgramPipeline(
-	GlProgramHandle frag)
+Error Renderer::createDrawQuadProgramPipeline(
+	GlProgramHandle frag, GlProgramPipelineHandle& ppline)
 {
 {
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(m_gl);
+	Error err = cmdBuff.create(m_gl);
 
 
-	Array<GlProgramHandle, 2> progs = {{m_drawQuadVert->getGlProgram(), frag}};
+	if(!err)
+	{
+		Array<GlProgramHandle, 2> progs = 
+			{{m_drawQuadVert->getGlProgram(), frag}};
 
 
-	GlProgramPipelineHandle ppline;
-	ppline.create(cmdBuff, &progs[0], &progs[0] + 2);
-	cmdBuff.finish();
+		err = ppline.create(cmdBuff, &progs[0], &progs[0] + 2);
+	}
+
+	if(!err)
+	{
+		cmdBuff.finish();
+	}
 
 
-	return ppline;
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 27 - 11
src/renderer/RenderingPass.cpp

@@ -34,57 +34,71 @@ ResourceManager& RenderingPass::getResourceManager()
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void BlurringRenderingPass::initBlurring(
+Error BlurringRenderingPass::initBlurring(
 	Renderer& r, U width, U height, U samples, F32 blurringDistance)
 	Renderer& r, U width, U height, U samples, F32 blurringDistance)
 {
 {
+	Error err = ErrorCode::NONE;
 	GlDevice& gl = getGlDevice();
 	GlDevice& gl = getGlDevice();
 	GlCommandBufferHandle cmdb;
 	GlCommandBufferHandle cmdb;
-	cmdb.create(&gl);
+	err = cmdb.create(&gl);
+	if(err) return err;
 
 
-	Array<String, 2> pps = {{String(getAllocator()), String(getAllocator())}};
+	Array<String, 2> pps;
+	String::ScopeDestroyer ppsd0(&pps[0], getAllocator());
+	String::ScopeDestroyer ppsd1(&pps[1], getAllocator());
 
 
-	pps[1].sprintf("#define HPASS\n"
+	err = pps[1].sprintf(getAllocator(),
+		"#define HPASS\n"
 		"#define COL_RGB\n"
 		"#define COL_RGB\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES %u\n", 
 		"#define SAMPLES %u\n", 
 		blurringDistance, height, samples);
 		blurringDistance, height, samples);
+	if(err) return err;
 
 
-	pps[0].sprintf("#define VPASS\n"
+	err = pps[0].sprintf(getAllocator(),
+		"#define VPASS\n"
 		"#define COL_RGB\n"
 		"#define COL_RGB\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define BLURRING_DIST float(%f)\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES %u\n",
 		"#define SAMPLES %u\n",
 		blurringDistance, width, samples);
 		blurringDistance, width, samples);
+	if(err) return err;
 
 
 	for(U i = 0; i < 2; i++)
 	for(U i = 0; i < 2; i++)
 	{
 	{
 		Direction& dir = m_dirs[i];
 		Direction& dir = m_dirs[i];
 
 
-		r.createRenderTarget(width, height, GL_RGB8, GL_RGB, 
+		err = r.createRenderTarget(width, height, GL_RGB8, GL_RGB, 
 			GL_UNSIGNED_BYTE, 1, dir.m_rt);
 			GL_UNSIGNED_BYTE, 1, dir.m_rt);
+		if(err) return err;
 
 
 		// Set to bilinear because the blurring techniques take advantage of 
 		// Set to bilinear because the blurring techniques take advantage of 
 		// that
 		// that
 		dir.m_rt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
 		dir.m_rt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
 
 
 		// Create FB
 		// Create FB
-		dir.m_fb.create(
+		err = dir.m_fb.create(
 			cmdb, {{dir.m_rt, GL_COLOR_ATTACHMENT0}});
 			cmdb, {{dir.m_rt, GL_COLOR_ATTACHMENT0}});
+		if(err) return err;
 
 
-		dir.m_frag.loadToCache(&getResourceManager(),
+		err = dir.m_frag.loadToCache(&getResourceManager(),
 			"shaders/VariableSamplingBlurGeneric.frag.glsl", 
 			"shaders/VariableSamplingBlurGeneric.frag.glsl", 
 			pps[i].toCString(), "r_");
 			pps[i].toCString(), "r_");
+		if(err) return err;
 
 
-		dir.m_ppline = 
-			r.createDrawQuadProgramPipeline(dir.m_frag->getGlProgram());
+		err = r.createDrawQuadProgramPipeline(
+			dir.m_frag->getGlProgram(), dir.m_ppline);
+		if(err) return err;
 	}
 	}
 
 
 	cmdb.finish();
 	cmdb.finish();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void BlurringRenderingPass::runBlurring(
+Error BlurringRenderingPass::runBlurring(
 	Renderer& r, GlCommandBufferHandle& cmdb)
 	Renderer& r, GlCommandBufferHandle& cmdb)
 {
 {
 	// H pass input
 	// H pass input
@@ -105,6 +119,8 @@ void BlurringRenderingPass::runBlurring(
 		m_dirs[enumToValue(DirectionEnum::VERTICAL)].m_ppline.bind(cmdb);
 		m_dirs[enumToValue(DirectionEnum::VERTICAL)].m_ppline.bind(cmdb);
 		r.drawQuad(cmdb);
 		r.drawQuad(cmdb);
 	}
 	}
+
+	return ErrorCode::NONE;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 42 - 22
src/renderer/Sm.cpp

@@ -15,13 +15,14 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-void Sm::init(const ConfigSet& initializer)
+Error Sm::init(const ConfigSet& initializer)
 {
 {
+	Error err = ErrorCode::NONE;
 	m_enabled = initializer.get("is.sm.enabled");
 	m_enabled = initializer.get("is.sm.enabled");
 
 
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return err;
 	}
 	}
 
 
 	m_poissonEnabled = initializer.get("is.sm.poissonEnabled");
 	m_poissonEnabled = initializer.get("is.sm.poissonEnabled");
@@ -33,7 +34,8 @@ void Sm::init(const ConfigSet& initializer)
 	//
 	//
 	if(initializer.get("is.sm.maxLights") > MAX_SHADOW_CASTERS)
 	if(initializer.get("is.sm.maxLights") > MAX_SHADOW_CASTERS)
 	{
 	{
-		throw ANKI_EXCEPTION("Too many shadow casters");
+		ANKI_LOGE("Too many shadow casters");
+		return ErrorCode::FUNCTION_FAILED;
 	}
 	}
 
 
 	// Create shadowmaps array
 	// Create shadowmaps array
@@ -56,9 +58,11 @@ void Sm::init(const ConfigSet& initializer)
 	}
 	}
 
 
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
 
 
-	m_sm2DArrayTex.create(cmdBuff, sminit);
+	err = m_sm2DArrayTex.create(cmdBuff, sminit);
+	if(err) return err;
 
 
 	m_sm2DArrayTex.setParameter(cmdBuff, 
 	m_sm2DArrayTex.setParameter(cmdBuff, 
 		GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
 		GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
@@ -66,17 +70,20 @@ void Sm::init(const ConfigSet& initializer)
 
 
 	// Init sms
 	// Init sms
 	U32 layer = 0;
 	U32 layer = 0;
-	m_sms.resize(initializer.get("is.sm.maxLights"));
+	err = m_sms.create(getAllocator(), initializer.get("is.sm.maxLights"));
 	for(Shadowmap& sm : m_sms)
 	for(Shadowmap& sm : m_sms)
 	{
 	{
 		sm.m_layerId = layer;
 		sm.m_layerId = layer;
-		sm.m_fb.create(cmdBuff, 
+		err = sm.m_fb.create(cmdBuff, 
 			{{m_sm2DArrayTex, GL_DEPTH_ATTACHMENT, (U32)layer}});
 			{{m_sm2DArrayTex, GL_DEPTH_ATTACHMENT, (U32)layer}});
+		if(err) return err;
 
 
 		++layer;
 		++layer;
 	}
 	}
 
 
 	cmdBuff.flush();
 	cmdBuff.flush();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -106,22 +113,28 @@ void Sm::finishDraw(GlCommandBufferHandle& cmdBuff)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Sm::run(Light* shadowCasters[], U32 shadowCastersCount, 
+Error Sm::run(Light* shadowCasters[], U32 shadowCastersCount, 
 	GlCommandBufferHandle& cmdBuff)
 	GlCommandBufferHandle& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	prepareDraw(cmdBuff);
 	prepareDraw(cmdBuff);
 
 
 	// render all
 	// render all
 	for(U32 i = 0; i < shadowCastersCount; i++)
 	for(U32 i = 0; i < shadowCastersCount; i++)
 	{
 	{
-		Shadowmap* sm = doLight(*shadowCasters[i], cmdBuff);
+		Shadowmap* sm;
+		err = doLight(*shadowCasters[i], cmdBuff, sm);
+		if(err) return err;
+
 		ANKI_ASSERT(sm != nullptr);
 		ANKI_ASSERT(sm != nullptr);
 		(void)sm;
 		(void)sm;
 	}
 	}
 
 
 	finishDraw(cmdBuff);
 	finishDraw(cmdBuff);
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -149,7 +162,7 @@ Sm::Shadowmap& Sm::bestCandidate(Light& light)
 
 
 	// Find an old and replace it
 	// Find an old and replace it
 	Shadowmap* sm = &m_sms[0];
 	Shadowmap* sm = &m_sms[0];
-	for(U i = 1; i < m_sms.size(); i++)
+	for(U i = 1; i < m_sms.getSize(); i++)
 	{
 	{
 		if(m_sms[i].m_timestamp < sm->m_timestamp)
 		if(m_sms[i].m_timestamp < sm->m_timestamp)
 		{
 		{
@@ -163,9 +176,12 @@ Sm::Shadowmap& Sm::bestCandidate(Light& light)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Sm::Shadowmap* Sm::doLight(Light& light, GlCommandBufferHandle& cmdBuff)
+Error Sm::doLight(
+	Light& light, GlCommandBufferHandle& cmdBuff, Sm::Shadowmap*& sm)
 {
 {
-	Shadowmap& sm = bestCandidate(light);
+	Error err = ErrorCode::NONE;
+
+	sm = &bestCandidate(light);
 
 
 	FrustumComponent& fr = light.getComponent<FrustumComponent>();
 	FrustumComponent& fr = light.getComponent<FrustumComponent>();
 	VisibilityTestResults& vi = fr.getVisibilityTestResults();
 	VisibilityTestResults& vi = fr.getVisibilityTestResults();
@@ -176,9 +192,11 @@ Sm::Shadowmap* Sm::doLight(Light& light, GlCommandBufferHandle& cmdBuff)
 	U32 lastUpdate = light.MoveComponent::getTimestamp();
 	U32 lastUpdate = light.MoveComponent::getTimestamp();
 	lastUpdate = std::max(lastUpdate, fr.getTimestamp());
 	lastUpdate = std::max(lastUpdate, fr.getTimestamp());
 
 
-	for(auto& it : vi.m_renderables)
+	auto it = vi.getRenderablesBegin();
+	auto end = vi.getRenderablesEnd();
+	for(; it != end; ++it)
 	{
 	{
-		SceneNode* node = it.m_node;
+		SceneNode* node = it->m_node;
 
 
 		FrustumComponent* bfr = node->tryGetComponent<FrustumComponent>();
 		FrustumComponent* bfr = node->tryGetComponent<FrustumComponent>();
 		if(bfr)
 		if(bfr)
@@ -199,30 +217,32 @@ Sm::Shadowmap* Sm::doLight(Light& light, GlCommandBufferHandle& cmdBuff)
 		}
 		}
 	}
 	}
 
 
-	Bool shouldUpdate = lastUpdate >= sm.m_timestamp;
+	Bool shouldUpdate = lastUpdate >= sm->m_timestamp;
 	if(!shouldUpdate)
 	if(!shouldUpdate)
 	{
 	{
-		return &sm;
+		return err;
 	}
 	}
 
 
-	sm.m_timestamp = getGlobTimestamp();
-	light.setShadowMapIndex(&sm - &m_sms[0]);
+	sm->m_timestamp = getGlobTimestamp();
+	light.setShadowMapIndex(sm - &m_sms[0]);
 
 
 	//
 	//
 	// Render
 	// Render
 	//
 	//
-	sm.m_fb.bind(cmdBuff, true);
+	sm->m_fb.bind(cmdBuff, true);
 	cmdBuff.setViewport(0, 0, m_resolution, m_resolution);
 	cmdBuff.setViewport(0, 0, m_resolution, m_resolution);
 	cmdBuff.clearBuffers(GL_DEPTH_BUFFER_BIT);
 	cmdBuff.clearBuffers(GL_DEPTH_BUFFER_BIT);
 
 
-	for(auto& it : vi.m_renderables)
+	it = vi.getRenderablesBegin();
+	for(; it != end; ++it)
 	{
 	{
-		m_r->getSceneDrawer().render(light, it);
+		err = m_r->getSceneDrawer().render(light, *it);
+		if(err) break;
 	}
 	}
 
 
 	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, (U64)1);
 	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, (U64)1);
 
 
-	return &sm;
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 76 - 39
src/renderer/Ssao.cpp

@@ -67,30 +67,39 @@ public:
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-void Ssao::createFb(GlFramebufferHandle& fb, GlTextureHandle& rt)
+Error Ssao::createFb(GlFramebufferHandle& fb, GlTextureHandle& rt)
 {
 {
-	m_r->createRenderTarget(m_width, m_height, GL_RED, GL_RED, 
+	Error err = ErrorCode::NONE;
+
+	err = m_r->createRenderTarget(m_width, m_height, GL_RED, GL_RED, 
 		GL_UNSIGNED_BYTE, 1, rt);
 		GL_UNSIGNED_BYTE, 1, rt);
+	if(err) return err;
 
 
 	// Set to bilinear because the blurring techniques take advantage of that
 	// Set to bilinear because the blurring techniques take advantage of that
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
 	rt.setFilter(cmdBuff, GlTextureHandle::Filter::LINEAR);
 	rt.setFilter(cmdBuff, GlTextureHandle::Filter::LINEAR);
 
 
 	// create FB
 	// create FB
-	fb.create(cmdBuff, {{rt, GL_COLOR_ATTACHMENT0}});
+	err = fb.create(cmdBuff, {{rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
 
 
 	cmdBuff.flush();
 	cmdBuff.flush();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ssao::initInternal(const ConfigSet& config)
+Error Ssao::initInternal(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_enabled = config.get("pps.ssao.enabled");
 	m_enabled = config.get("pps.ssao.enabled");
 
 
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return err;
 	}
 	}
 
 
 	m_blurringIterationsCount = 
 	m_blurringIterationsCount = 
@@ -109,18 +118,22 @@ void Ssao::initInternal(const ConfigSet& config)
 	//
 	//
 	// create FBOs
 	// create FBOs
 	//
 	//
-	createFb(m_hblurFb, m_hblurRt);
-	createFb(m_vblurFb, m_vblurRt);
+	err = createFb(m_hblurFb, m_hblurRt);
+	if(err) return err;
+	err = createFb(m_vblurFb, m_vblurRt);
+	if(err) return err;
 
 
 	//
 	//
 	// noise texture
 	// noise texture
 	//
 	//
 	GlCommandBufferHandle cmdb;
 	GlCommandBufferHandle cmdb;
-	cmdb.create(&getGlDevice());
+	err = cmdb.create(&getGlDevice());
+	if(err) return err;
 
 
 	GlClientBufferHandle noise;
 	GlClientBufferHandle noise;
-	noise.create(
+	err = noise.create(
 		cmdb, sizeof(Vec3) * NOISE_TEX_SIZE * NOISE_TEX_SIZE, nullptr);
 		cmdb, sizeof(Vec3) * NOISE_TEX_SIZE * NOISE_TEX_SIZE, nullptr);
+	if(err) return err;
 
 
 	genNoise((Vec3*)noise.getBaseAddress(), 
 	genNoise((Vec3*)noise.getBaseAddress(), 
 		(Vec3*)((U8*)noise.getBaseAddress() + noise.getSize()));
 		(Vec3*)((U8*)noise.getBaseAddress() + noise.getSize()));
@@ -142,96 +155,117 @@ void Ssao::initInternal(const ConfigSet& config)
 	//
 	//
 	// Kernel
 	// Kernel
 	//
 	//
-	String kernelStr(getAllocator());
+	String kernelStr;
+	String::ScopeDestroyer kernelStrd(&kernelStr, getAllocator());
 	Array<Vec3, KERNEL_SIZE> kernel;
 	Array<Vec3, KERNEL_SIZE> kernel;
 
 
 	genKernel(kernel.begin(), kernel.end());
 	genKernel(kernel.begin(), kernel.end());
-	kernelStr = "vec3[](";
+	err = kernelStr.create(getAllocator(), "vec3[](");
+	if(err) return err;
 	for(U i = 0; i < kernel.size(); i++)
 	for(U i = 0; i < kernel.size(); i++)
 	{
 	{
-		String tmp(getAllocator());
+		String tmp;
+		String::ScopeDestroyer tmpd(&tmp, getAllocator());
 
 
-		tmp.sprintf("vec3(%f, %f, %f) %s",
+		err = tmp.sprintf(getAllocator(),
+			"vec3(%f, %f, %f) %s",
 			kernel[i].x(), kernel[i].y(), kernel[i].z(),
 			kernel[i].x(), kernel[i].y(), kernel[i].z(),
 			(i != kernel.size() - 1) ? ", " : ")");
 			(i != kernel.size() - 1) ? ", " : ")");
+		if(err) return err;
 
 
-		kernelStr += tmp;
+		err = kernelStr.append(getAllocator(), tmp);
+		if(err) return err;
 	}
 	}
 
 
 	//
 	//
 	// Shaders
 	// Shaders
 	//
 	//
-	m_uniformsBuff.create(cmdb, GL_SHADER_STORAGE_BUFFER, 
+	err = m_uniformsBuff.create(cmdb, GL_SHADER_STORAGE_BUFFER, 
 		sizeof(ShaderCommonUniforms), GL_DYNAMIC_STORAGE_BIT);
 		sizeof(ShaderCommonUniforms), GL_DYNAMIC_STORAGE_BIT);
+	if(err) return err;
 
 
-	String pps(getAllocator());
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
 
 
 	// main pass prog
 	// main pass prog
-	pps.sprintf(
+	err = pps.sprintf(getAllocator(),
 		"#define NOISE_MAP_SIZE %u\n"
 		"#define NOISE_MAP_SIZE %u\n"
 		"#define WIDTH %u\n"
 		"#define WIDTH %u\n"
 		"#define HEIGHT %u\n"
 		"#define HEIGHT %u\n"
 		"#define KERNEL_SIZE %u\n"
 		"#define KERNEL_SIZE %u\n"
 		"#define KERNEL_ARRAY %s\n",
 		"#define KERNEL_ARRAY %s\n",
 		NOISE_TEX_SIZE, m_width, m_height, KERNEL_SIZE, &kernelStr[0]);
 		NOISE_TEX_SIZE, m_width, m_height, KERNEL_SIZE, &kernelStr[0]);
+	if(err) return err;
 
 
-	m_ssaoFrag.loadToCache(&getResourceManager(),
+	err = m_ssaoFrag.loadToCache(&getResourceManager(),
 		"shaders/PpsSsao.frag.glsl", pps.toCString(), "r_");
 		"shaders/PpsSsao.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-
-	m_ssaoPpline = m_r->createDrawQuadProgramPipeline(
-		m_ssaoFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_ssaoFrag->getGlProgram(), m_ssaoPpline);
+	if(err) return err;
 
 
 	// blurring progs
 	// blurring progs
 	const char* SHADER_FILENAME = 
 	const char* SHADER_FILENAME = 
 		"shaders/VariableSamplingBlurGeneric.frag.glsl";
 		"shaders/VariableSamplingBlurGeneric.frag.glsl";
 
 
-	pps.sprintf(
+	pps.destroy(getAllocator());
+	err = pps.sprintf(getAllocator(),
 		"#define HPASS\n"
 		"#define HPASS\n"
 		"#define COL_R\n"
 		"#define COL_R\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES 7\n", 
 		"#define SAMPLES 7\n", 
 		m_height);
 		m_height);
+	if(err) return err;
 
 
-	m_hblurFrag.loadToCache(&getResourceManager(),
+	err = m_hblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_");
 		SHADER_FILENAME, pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_hblurPpline = m_r->createDrawQuadProgramPipeline(
-		m_hblurFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_hblurFrag->getGlProgram(), m_hblurPpline);
+	if(err) return err;
 
 
-	pps.sprintf(
+	pps.destroy(getAllocator());
+	err = pps.sprintf(getAllocator(),
 		"#define VPASS\n"
 		"#define VPASS\n"
 		"#define COL_R\n"
 		"#define COL_R\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define IMG_DIMENSION %u\n"
 		"#define SAMPLES 7\n", 
 		"#define SAMPLES 7\n", 
 		m_width);
 		m_width);
+	if(err) return err;
 
 
-	m_vblurFrag.loadToCache(&getResourceManager(),
+	err = m_vblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_");
 		SHADER_FILENAME, pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_vblurPpline = m_r->createDrawQuadProgramPipeline(
-		m_vblurFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_vblurFrag->getGlProgram(), m_vblurPpline);
+	if(err) return err;
 
 
 	cmdb.flush();
 	cmdb.flush();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ssao::init(const ConfigSet& config)
+Error Ssao::init(const ConfigSet& config)
 {
 {
-	try
+	Error err = initInternal(config);
+	
+	if(err)
 	{
 	{
-		initInternal(config);
-	}
-	catch(const std::exception& e)
-	{
-		throw ANKI_EXCEPTION("Failed to init PPS SSAO") << e;
+		ANKI_LOGE("Failed to init PPS SSAO");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Ssao::run(GlCommandBufferHandle& cmdb)
+Error Ssao::run(GlCommandBufferHandle& cmdb)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	const Camera& cam = m_r->getSceneGraph().getActiveCamera();
 	const Camera& cam = m_r->getSceneGraph().getActiveCamera();
 
 
@@ -257,8 +291,9 @@ void Ssao::run(GlCommandBufferHandle& cmdb)
 		|| m_commonUboUpdateTimestamp == 1)
 		|| m_commonUboUpdateTimestamp == 1)
 	{
 	{
 		GlClientBufferHandle tmpBuff;
 		GlClientBufferHandle tmpBuff;
-		tmpBuff.create(cmdb, sizeof(ShaderCommonUniforms),
+		err = tmpBuff.create(cmdb, sizeof(ShaderCommonUniforms),
 			nullptr);
 			nullptr);
+		if(err) return err;
 
 
 		ShaderCommonUniforms& blk = 
 		ShaderCommonUniforms& blk = 
 			*((ShaderCommonUniforms*)tmpBuff.getBaseAddress());
 			*((ShaderCommonUniforms*)tmpBuff.getBaseAddress());
@@ -294,6 +329,8 @@ void Ssao::run(GlCommandBufferHandle& cmdb)
 		m_vblurPpline.bind(cmdb);
 		m_vblurPpline.bind(cmdb);
 		m_r->drawQuad(cmdb);
 		m_r->drawQuad(cmdb);
 	}
 	}
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 32 - 15
src/renderer/Sslr.cpp

@@ -10,13 +10,15 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-void Sslr::init(const ConfigSet& config)
+Error Sslr::init(const ConfigSet& config)
 {
 {
+	Error err = ErrorCode::NONE;
+
 	m_enabled = config.get("pps.sslr.enabled");
 	m_enabled = config.get("pps.sslr.enabled");
 
 
 	if(!m_enabled)
 	if(!m_enabled)
 	{
 	{
-		return;
+		return err;
 	}
 	}
 
 
 	// Size
 	// Size
@@ -30,29 +32,37 @@ void Sslr::init(const ConfigSet& config)
 	alignRoundUp(16, m_height);
 	alignRoundUp(16, m_height);
 
 
 	// Programs
 	// Programs
-	String pps(getAllocator());
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
 
 
-	pps.sprintf(
+	err = pps.sprintf(getAllocator(),
 		"#define WIDTH %u\n"
 		"#define WIDTH %u\n"
 		"#define HEIGHT %u\n",
 		"#define HEIGHT %u\n",
 		m_width, m_height);
 		m_width, m_height);
+	if(err) return err;
 
 
-	m_reflectionFrag.loadToCache(&getResourceManager(),
+	err = m_reflectionFrag.loadToCache(&getResourceManager(),
 		"shaders/PpsSslr.frag.glsl", pps.toCString(), "r_");
 		"shaders/PpsSslr.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_reflectionPpline = m_r->createDrawQuadProgramPipeline(
-		m_reflectionFrag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(
+		m_reflectionFrag->getGlProgram(), m_reflectionPpline);
+	if(err) return err;
 
 
 	// Sampler
 	// Sampler
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
-	m_depthMapSampler.create(cmdBuff);
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
+	err = m_depthMapSampler.create(cmdBuff);
+	if(err) return err;
 	m_depthMapSampler.setFilter(cmdBuff, GlSamplerHandle::Filter::NEAREST);
 	m_depthMapSampler.setFilter(cmdBuff, GlSamplerHandle::Filter::NEAREST);
 
 
 	// Blit
 	// Blit
-	m_blitFrag.load("shaders/Blit.frag.glsl", &getResourceManager());
-	m_blitPpline = m_r->createDrawQuadProgramPipeline(
-		m_blitFrag->getGlProgram());
+	err = m_blitFrag.load("shaders/Blit.frag.glsl", &getResourceManager());
+	if(err) return err;
+	err = m_r->createDrawQuadProgramPipeline(
+		m_blitFrag->getGlProgram(), m_blitPpline);
+	if(err) return err;
 
 
 	// Init FBOs and RTs and blurring
 	// Init FBOs and RTs and blurring
 	if(m_blurringIterationsCount > 0)
 	if(m_blurringIterationsCount > 0)
@@ -63,24 +73,29 @@ void Sslr::init(const ConfigSet& config)
 	{
 	{
 		Direction& dir = m_dirs[(U)DirectionEnum::VERTICAL];
 		Direction& dir = m_dirs[(U)DirectionEnum::VERTICAL];
 
 
-		m_r->createRenderTarget(m_width, m_height, GL_RGB8, GL_RGB, 
+		err = m_r->createRenderTarget(m_width, m_height, GL_RGB8, GL_RGB, 
 			GL_UNSIGNED_BYTE, 1, dir.m_rt);
 			GL_UNSIGNED_BYTE, 1, dir.m_rt);
+		if(err) return err;
 
 
 		// Set to bilinear because the blurring techniques take advantage of 
 		// Set to bilinear because the blurring techniques take advantage of 
 		// that
 		// that
 		dir.m_rt.setFilter(cmdBuff, GlTextureHandle::Filter::LINEAR);
 		dir.m_rt.setFilter(cmdBuff, GlTextureHandle::Filter::LINEAR);
 
 
 		// Create FB
 		// Create FB
-		dir.m_fb.create(cmdBuff, {{dir.m_rt, GL_COLOR_ATTACHMENT0}});
+		err = dir.m_fb.create(cmdBuff, {{dir.m_rt, GL_COLOR_ATTACHMENT0}});
+		if(err) return err;
 	}
 	}
 
 
 	cmdBuff.finish();
 	cmdBuff.finish();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Sslr::run(GlCommandBufferHandle& cmdBuff)
+Error Sslr::run(GlCommandBufferHandle& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
 
 
 	// Compute the reflection
 	// Compute the reflection
 	//
 	//
@@ -123,6 +138,8 @@ void Sslr::run(GlCommandBufferHandle& cmdBuff)
 	m_r->drawQuad(cmdBuff);
 	m_r->drawQuad(cmdBuff);
 
 
 	cmdBuff.enableBlend(false);
 	cmdBuff.enableBlend(false);
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 46 - 26
src/renderer/Tiler.cpp

@@ -18,12 +18,13 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-#define CHECK_PLANE_PTR(p_) \
-	ANKI_ASSERT(U(p_ - &m_tiler->m_allPlanes[0]) < m_tiler->m_allPlanes.size());
+#define CHECK_PLANE_PTR(p_) ANKI_ASSERT(U(p_ - &m_tiler->m_allPlanes[0]) \
+	< m_tiler->m_allPlanes.getSize());
 
 
 /// Job that updates the left, right, top and buttom tile planes
 /// Job that updates the left, right, top and buttom tile planes
-struct UpdatePlanesPerspectiveCameraJob: Threadpool::Task
+class UpdatePlanesPerspectiveCameraTask: public Threadpool::Task
 {
 {
+public:
 	Tiler* m_tiler = nullptr;
 	Tiler* m_tiler = nullptr;
 	PerspectiveCamera* m_cam = nullptr;
 	PerspectiveCamera* m_cam = nullptr;
 	Bool m_frustumChanged;
 	Bool m_frustumChanged;
@@ -31,7 +32,7 @@ struct UpdatePlanesPerspectiveCameraJob: Threadpool::Task
 	const PixelArray* m_pixels = nullptr;
 	const PixelArray* m_pixels = nullptr;
 #endif
 #endif
 
 
-	void operator()(U32 threadId, PtrSize threadsCount)
+	Error operator()(U32 threadId, PtrSize threadsCount)
 	{
 	{
 #if ANKI_TILER_ENABLE_GPU
 #if ANKI_TILER_ENABLE_GPU
 		ANKI_ASSERT(tiler && cam && pixels);
 		ANKI_ASSERT(tiler && cam && pixels);
@@ -152,6 +153,8 @@ struct UpdatePlanesPerspectiveCameraJob: Threadpool::Task
 			++farPlanesW;
 			++farPlanesW;
 		}
 		}
 #endif
 #endif
+
+		return ErrorCode::NONE;
 	}
 	}
 
 
 	/// Calculate and set a top looking plane
 	/// Calculate and set a top looking plane
@@ -206,27 +209,33 @@ Tiler::Tiler(Renderer* r)
 
 
 //==============================================================================
 //==============================================================================
 Tiler::~Tiler()
 Tiler::~Tiler()
-{}
+{
+	m_allPlanes.destroy(getAllocator());
+}
 
 
 //==============================================================================
 //==============================================================================
-void Tiler::init()
+Error Tiler::init()
 {
 {
-	try
-	{
-		initInternal();
-	}
-	catch(const std::exception& e)
+	Error err = initInternal();
+	
+	if(err)
 	{
 	{
-		throw ANKI_EXCEPTION("Failed to init tiler") << e;
+		ANKI_LOGE("Failed to init tiler");
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Tiler::initInternal()
+Error Tiler::initInternal()
 {
 {
+	Error err = ErrorCode::NONE;
+
 	// Load the program
 	// Load the program
-	String pps(getAllocator());
-	pps.sprintf(
+	String pps;
+	String::ScopeDestroyer ppsd(&pps, getAllocator());
+
+	err = pps.sprintf(getAllocator(),
 		"#define TILES_X_COUNT %u\n"
 		"#define TILES_X_COUNT %u\n"
 		"#define TILES_Y_COUNT %u\n"
 		"#define TILES_Y_COUNT %u\n"
 		"#define RENDERER_WIDTH %u\n"
 		"#define RENDERER_WIDTH %u\n"
@@ -235,27 +244,35 @@ void Tiler::initInternal()
 		m_r->getTilesCount().y(),
 		m_r->getTilesCount().y(),
 		m_r->getWidth(),
 		m_r->getWidth(),
 		m_r->getHeight());
 		m_r->getHeight());
+	if(err) return err;
 
 
-	m_frag.loadToCache(&getResourceManager(),
+	err = m_frag.loadToCache(&getResourceManager(),
 		"shaders/TilerMinMax.frag.glsl", pps.toCString(), "r_");
 		"shaders/TilerMinMax.frag.glsl", pps.toCString(), "r_");
+	if(err) return err;
 
 
-	m_ppline = m_r->createDrawQuadProgramPipeline(m_frag->getGlProgram());
+	err = m_r->createDrawQuadProgramPipeline(m_frag->getGlProgram(), m_ppline);
+	if(err) return err;
 
 
 	// Create FB
 	// Create FB
-	m_r->createRenderTarget(m_r->getTilesCount().x(), m_r->getTilesCount().y(),
+	err = m_r->createRenderTarget(
+		m_r->getTilesCount().x(), m_r->getTilesCount().y(),
 		GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, 1, m_rt);
 		GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, 1, m_rt);
+	if(err) return err;
 
 
 	GlCommandBufferHandle cmdBuff;
 	GlCommandBufferHandle cmdBuff;
-	cmdBuff.create(&getGlDevice());
+	err = cmdBuff.create(&getGlDevice());
+	if(err) return err;
 
 
-	m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	err = m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}});
+	if(err) return err;
 
 
 	// Create PBO
 	// Create PBO
 	U pixelBuffSize = m_r->getTilesCount().x() * m_r->getTilesCount().y();
 	U pixelBuffSize = m_r->getTilesCount().x() * m_r->getTilesCount().y();
 	pixelBuffSize *= 2 * sizeof(F32); // The pixel size
 	pixelBuffSize *= 2 * sizeof(F32); // The pixel size
 	pixelBuffSize *= 4; // Because it will be always mapped
 	pixelBuffSize *= 4; // Because it will be always mapped
-	m_pixelBuff.create(cmdBuff, GL_PIXEL_PACK_BUFFER, pixelBuffSize,
+	err = m_pixelBuff.create(cmdBuff, GL_PIXEL_PACK_BUFFER, pixelBuffSize,
 		GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
 		GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
+	if(err) return err;
 
 
 	// Init planes. One plane for each direction, plus near/far plus the world
 	// Init planes. One plane for each direction, plus near/far plus the world
 	// space of those
 	// space of those
@@ -264,8 +281,8 @@ void Tiler::initInternal()
 		+ (m_r->getTilesCount().y() - 1) * 2  // planes I
 		+ (m_r->getTilesCount().y() - 1) * 2  // planes I
 		+ (m_r->getTilesCount().x() * m_r->getTilesCount().y() * 2); // near+far
 		+ (m_r->getTilesCount().x() * m_r->getTilesCount().y() * 2); // near+far
 
 
-	m_allPlanes = std::move(Vector<Plane>(getAllocator()));
-	m_allPlanes.resize(planesCount);
+	err = m_allPlanes.create(getAllocator(), planesCount);
+	if(err) return err;
 
 
 	m_planesX = &m_allPlanes[0];
 	m_planesX = &m_allPlanes[0];
 	m_planesY = m_planesX + m_r->getTilesCount().x() - 1;
 	m_planesY = m_planesX + m_r->getTilesCount().x() - 1;
@@ -277,9 +294,11 @@ void Tiler::initInternal()
 		m_nearPlanesW + m_r->getTilesCount().x() * m_r->getTilesCount().y();
 		m_nearPlanesW + m_r->getTilesCount().x() * m_r->getTilesCount().y();
 
 
 	ANKI_ASSERT(m_farPlanesW + m_r->getTilesCount().x() 
 	ANKI_ASSERT(m_farPlanesW + m_r->getTilesCount().x() 
-		* m_r->getTilesCount().y() ==  &m_allPlanes[0] + m_allPlanes.size());
+		* m_r->getTilesCount().y() ==  &m_allPlanes[0] + m_allPlanes.getSize());
 
 
 	cmdBuff.flush();
 	cmdBuff.flush();
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -321,7 +340,7 @@ void Tiler::updateTiles(Camera& cam)
 	//
 	//
 	// Issue parallel jobs
 	// Issue parallel jobs
 	//
 	//
-	Array<UpdatePlanesPerspectiveCameraJob, Threadpool::MAX_THREADS> jobs;
+	Array<UpdatePlanesPerspectiveCameraTask, Threadpool::MAX_THREADS> jobs;
 	U32 camTimestamp = cam.FrustumComponent::getTimestamp();
 	U32 camTimestamp = cam.FrustumComponent::getTimestamp();
 
 
 	// Do a job that transforms only the planes when:
 	// Do a job that transforms only the planes when:
@@ -358,7 +377,8 @@ void Tiler::updateTiles(Camera& cam)
 	}
 	}
 
 
 	// Sync threads
 	// Sync threads
-	threadPool.waitForAllThreadsToFinish();
+	Error err = threadPool.waitForAllThreadsToFinish();
+	(void)err;
 
 
 	// 
 	// 
 	// Misc
 	// Misc

+ 26 - 14
src/resource/AsyncLoader.cpp

@@ -9,12 +9,9 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-AsyncLoader::AsyncLoader(const HeapAllocator<U8>& alloc)
-:	m_alloc(alloc),
-	m_thread("anki_asyload")
-{
-	m_thread.start(this, threadCallback);
-}
+AsyncLoader::AsyncLoader()
+:	m_thread("anki_asyload")
+{}
 
 
 //==============================================================================
 //==============================================================================
 AsyncLoader::~AsyncLoader()
 AsyncLoader::~AsyncLoader()
@@ -37,6 +34,14 @@ AsyncLoader::~AsyncLoader()
 	}
 	}
 }
 }
 
 
+//==============================================================================
+Error AsyncLoader::create(const HeapAllocator<U8>& alloc)
+{
+	m_alloc = alloc;
+	m_thread.start(this, threadCallback);
+	return ErrorCode::NONE;
+}
+
 //==============================================================================
 //==============================================================================
 void AsyncLoader::stop()
 void AsyncLoader::stop()
 {
 {
@@ -46,24 +51,25 @@ void AsyncLoader::stop()
 	}
 	}
 
 
 	m_condVar.notifyOne();
 	m_condVar.notifyOne();
-	m_thread.join();
+	Error err = m_thread.join();
+	(void)err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-I AsyncLoader::threadCallback(Thread::Info& info)
+Error AsyncLoader::threadCallback(Thread::Info& info)
 {
 {
 	AsyncLoader& self = 
 	AsyncLoader& self = 
 		*reinterpret_cast<AsyncLoader*>(info.m_userData);
 		*reinterpret_cast<AsyncLoader*>(info.m_userData);
 
 
-	self.threadWorker();
-
-	return 0;
+	return self.threadWorker();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void AsyncLoader::threadWorker()
+Error AsyncLoader::threadWorker()
 {
 {
-	while(true)
+	Error err = ErrorCode::NONE;
+
+	while(!err)
 	{
 	{
 		Task* task;
 		Task* task;
 
 
@@ -96,11 +102,17 @@ void AsyncLoader::threadWorker()
 		}
 		}
 
 
 		// Exec the task
 		// Exec the task
-		(*task)();
+		err = (*task)();
+		if(err)
+		{
+			ANKI_LOGE("Async loader task failed");
+		}
 
 
 		// Delete the task
 		// Delete the task
 		m_alloc.deleteInstance(task);
 		m_alloc.deleteInstance(task);
 	}
 	}
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 1 - 1
src/resource/MaterialProgramCreator.cpp

@@ -289,7 +289,7 @@ Error MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 		if(cstr)
 		if(cstr)
 		{
 		{
 			ANKI_CHECK(
 			ANKI_CHECK(
-				MPStringList::splitString(m_alloc, cstr, ' ', inpvar.m_value));
+				inpvar.m_value.splitString(m_alloc, cstr, ' '));
 		}
 		}
 
 
 		// <const>
 		// <const>

+ 1 - 2
src/resource/ProgramPrePreprocessor.cpp

@@ -78,8 +78,7 @@ Error ProgramPrePreprocessor::parseFileForPragmas(
 	File file;
 	File file;
 	ANKI_CHECK(file.open(filename, File::OpenFlag::READ));
 	ANKI_CHECK(file.open(filename, File::OpenFlag::READ));
 	ANKI_CHECK(file.readAllText(TempResourceAllocator<char>(m_alloc), txt));
 	ANKI_CHECK(file.readAllText(TempResourceAllocator<char>(m_alloc), txt));
-	ANKI_CHECK(PPPStringList::splitString(
-		m_alloc, txt.toCString(), '\n', lines));
+	ANKI_CHECK(lines.splitString(m_alloc, txt.toCString(), '\n'));
 	if(lines.getSize() < 1)
 	if(lines.getSize() < 1)
 	{
 	{
 		ANKI_LOGE("File is empty: %s", &filename[0]);
 		ANKI_LOGE("File is empty: %s", &filename[0]);

+ 4 - 2
src/resource/ResourceManager.cpp

@@ -86,12 +86,14 @@ Error ResourceManager::create(Initializer& init)
 #undef ANKI_RESOURCE
 #undef ANKI_RESOURCE
 
 
 	// Init the thread
 	// Init the thread
-	m_asyncLoader = m_alloc.newInstance<AsyncLoader>(m_alloc);
+	m_asyncLoader = m_alloc.newInstance<AsyncLoader>();
 	if(m_asyncLoader == nullptr)
 	if(m_asyncLoader == nullptr)
 	{
 	{
-		return ErrorCode::FUNCTION_FAILED;
+		return ErrorCode::OUT_OF_MEMORY;
 	}
 	}
 
 
+	err = m_asyncLoader->create(m_alloc);
+
 	return err;
 	return err;
 }
 }
 
 

+ 16 - 6
src/scene/Light.cpp

@@ -32,13 +32,21 @@ Light::Light(SceneGraph* scene, Type t)
 //==============================================================================
 //==============================================================================
 Error Light::create(const CString& name)
 Error Light::create(const CString& name)
 {
 {
-	Error err = SceneNode::create(name, 3 + 1);
+	Error err = SceneNode::create(name);
 	
 	
 	if(!err)
 	if(!err)
 	{
 	{
-		addComponent(static_cast<MoveComponent*>(this));
-		addComponent(static_cast<SpatialComponent*>(this));
-		addComponent(static_cast<LightComponent*>(this));
+		err = addComponent(static_cast<MoveComponent*>(this));
+	}
+
+	if(!err)
+	{
+		err = addComponent(static_cast<SpatialComponent*>(this));
+	}
+
+	if(!err)
+	{
+		err = addComponent(static_cast<LightComponent*>(this));
 	}
 	}
 
 
 	return err;
 	return err;
@@ -178,11 +186,13 @@ Error SpotLight::create(const CString& name)
 
 
 	if(!err)
 	if(!err)
 	{
 	{
-		addComponent(static_cast<FrustumComponent*>(this));
+		err = addComponent(static_cast<FrustumComponent*>(this));
+	}
 
 
+	if(!err)
+	{
 		const F32 ang = toRad(45.0);
 		const F32 ang = toRad(45.0);
 		const F32 dist = 1.0;
 		const F32 dist = 1.0;
-
 		m_frustum.setAll(ang, ang, 0.1, dist);
 		m_frustum.setAll(ang, ang, 0.1, dist);
 	}
 	}
 
 

+ 5 - 2
src/scene/MoveComponent.cpp

@@ -85,11 +85,14 @@ Bool MoveComponent::updateWorldTransform(SceneNode& node)
 			{
 			{
 				SceneNode& childNode = obj.downCast<SceneNode>();
 				SceneNode& childNode = obj.downCast<SceneNode>();
 
 
-				childNode.iterateComponentsOfType<MoveComponent>([](
-					MoveComponent& mov)
+				Error e = childNode.iterateComponentsOfType<MoveComponent>(
+					[](MoveComponent& mov) -> Error
 				{
 				{
 					mov.markForUpdate();
 					mov.markForUpdate();
+					return ErrorCode::NONE;
 				});
 				});
+
+				(void)e;
 			}
 			}
 
 
 			return ErrorCode::NONE;
 			return ErrorCode::NONE;

+ 212 - 108
src/scene/ParticleEmitter.cpp

@@ -200,112 +200,155 @@ void Particle::revive(const ParticleEmitter& pe,
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-ParticleEmitter::ParticleEmitter(
-	const CString& name, SceneGraph* scene,
-	const CString& filename)
-:	SceneNode(name, scene),
+ParticleEmitter::ParticleEmitter(SceneGraph* scene)
+:	SceneNode(scene),
 	SpatialComponent(this),
 	SpatialComponent(this),
 	MoveComponent(this),
 	MoveComponent(this),
-	RenderComponent(this),
-	m_particles(getSceneAllocator()),
-	m_transforms(getSceneAllocator())
+	RenderComponent(this)
+{}
+
+//==============================================================================
+ParticleEmitter::~ParticleEmitter()
 {
 {
-	addComponent(static_cast<MoveComponent*>(this));
-	addComponent(static_cast<SpatialComponent*>(this));
-	addComponent(static_cast<RenderComponent*>(this));
+	// Delete simple particles
+	if(m_simulationType == SimulationType::SIMPLE)
+	{
+		for(ParticleBase* part : m_particles)
+		{
+			getSceneAllocator().deleteInstance(part);
+		}
+	}
 
 
-	m_obb.setCenter(Vec4(0.0));
-	m_obb.setExtend(Vec4(1.0, 1.0, 1.0, 0.0));
-	m_obb.setRotation(Mat3x4::getIdentity());
+	m_particles.destroy(getSceneAllocator());
+	m_transforms.destroy(getSceneAllocator());
+}
 
 
-	// Load resource
-	m_particleEmitterResource.load(filename, &getResourceManager());
+//==============================================================================
+Error ParticleEmitter::create(
+	const CString& name, const CString& filename)
+{
+	Error err = SceneNode::create(name);
 
 
-	// copy the resource to me
-	ParticleEmitterProperties& me = *this;
-	const ParticleEmitterProperties& other =
-		m_particleEmitterResource->getProperties();
-	me = other;
+	if(!err)
+	{
+		err = addComponent(static_cast<MoveComponent*>(this));
+	}
 
 
-	if(m_usePhysicsEngine)
+	if(!err)
 	{
 	{
-		createParticlesSimulation(scene);
-		m_simulationType = SimulationType::PHYSICS_ENGINE;
+		err = addComponent(static_cast<SpatialComponent*>(this));
 	}
 	}
-	else
+
+	if(!err)
 	{
 	{
-		createParticlesSimpleSimulation(scene);
-		m_simulationType = SimulationType::SIMPLE;
+		err = addComponent(static_cast<RenderComponent*>(this));
 	}
 	}
 
 
-	m_timeLeftForNextEmission = 0.0;
-	RenderComponent::init();
+	if(!err)
+	{
+		m_obb.setCenter(Vec4(0.0));
+		m_obb.setExtend(Vec4(1.0, 1.0, 1.0, 0.0));
+		m_obb.setRotation(Mat3x4::getIdentity());
 
 
-	// Create the vertex buffer and object
-	//
-	PtrSize buffSize = m_maxNumOfParticles * VERT_SIZE * 3;
+		// Load resource
+		err = m_particleEmitterResource.load(filename, &getResourceManager());
+	}
 
 
-	GlDevice& gl = getSceneGraph()._getGlDevice();
-	GlCommandBufferHandle cmd;
-	cmd.create(&gl);
+	// copy the resource to me
+	if(!err)
+	{
+		ParticleEmitterProperties& me = *this;
+		const ParticleEmitterProperties& other =
+			m_particleEmitterResource->getProperties();
+		me = other;
 
 
-	m_vertBuff.create(cmd, GL_ARRAY_BUFFER, buffSize, 
-		GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
+		if(m_usePhysicsEngine)
+		{
+			err = createParticlesSimulation(&getSceneGraph());
+			m_simulationType = SimulationType::PHYSICS_ENGINE;
+		}
+		else
+		{
+			err = createParticlesSimpleSimulation();
+			m_simulationType = SimulationType::SIMPLE;
+		}
+	}
 
 
-	// TODO Optimize that to avoid serialization
-	cmd.finish();
+	if(!err)
+	{
+		err = RenderComponent::create();
+	}
 
 
-	m_vertBuffMapping = (U8*)m_vertBuff.getPersistentMappingAddress();
-}
+	// Create the vertex buffer and object
+	//
+	GlCommandBufferHandle cmd;
+	if(!err)
+	{
+		GlDevice& gl = getSceneGraph()._getGlDevice();
+		err = cmd.create(&gl);
+	}
 
 
-//==============================================================================
-ParticleEmitter::~ParticleEmitter()
-{
-	// Delete simple particles
-	if(m_simulationType == SimulationType::SIMPLE)
+	if(!err)
 	{
 	{
-		for(ParticleBase* part : m_particles)
-		{
-			getSceneAllocator().deleteInstance(part);
-		}
+		PtrSize buffSize = m_maxNumOfParticles * VERT_SIZE * 3;
+		err = m_vertBuff.create(cmd, GL_ARRAY_BUFFER, buffSize, 
+			GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
+	}
+
+	if(!err)
+	{
+		// TODO Optimize that to avoid serialization
+		cmd.finish();
+
+		m_vertBuffMapping = (U8*)m_vertBuff.getPersistentMappingAddress();
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::buildRendering(RenderingBuildData& data)
+Error ParticleEmitter::buildRendering(RenderingBuildData& data)
 {
 {
-	ANKI_ASSERT(data.m_subMeshIndicesCount <= m_transforms.size() + 1);
+	ANKI_ASSERT(data.m_subMeshIndicesCount <= m_transforms.getSize() + 1);
+
+	Error err = ErrorCode::NONE;
 
 
 	if(m_aliveParticlesCount == 0)
 	if(m_aliveParticlesCount == 0)
 	{
 	{
-		return;
+		return ErrorCode::NONE;
 	}
 	}
 
 
 	RenderingKey key = data.m_key;
 	RenderingKey key = data.m_key;
 	key.m_lod = 0;
 	key.m_lod = 0;
 
 
 	GlProgramPipelineHandle ppline;
 	GlProgramPipelineHandle ppline;
-	m_particleEmitterResource->getMaterial().getProgramPipeline(key, ppline);
+	err = m_particleEmitterResource->getMaterial().getProgramPipeline(
+		key, ppline);
+	
+	if(!err)
+	{
+		ppline.bind(data.m_jobs);
 
 
-	ppline.bind(data.m_jobs);
+		PtrSize offset = (getGlobTimestamp() % 3) * (m_vertBuff.getSize() / 3);
 
 
-	PtrSize offset = (getGlobTimestamp() % 3) * (m_vertBuff.getSize() / 3);
+		// Position
+		m_vertBuff.bindVertexBuffer(data.m_jobs, 
+			3, GL_FLOAT, false, VERT_SIZE, offset + 0, 0);
 
 
-	// Position
-	m_vertBuff.bindVertexBuffer(data.m_jobs, 
-		3, GL_FLOAT, false, VERT_SIZE, offset + 0, 0);
+		// Scale
+		m_vertBuff.bindVertexBuffer(data.m_jobs, 
+			1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 3, 6);
 
 
-	// Scale
-	m_vertBuff.bindVertexBuffer(data.m_jobs, 
-		1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 3, 6);
+		// Alpha
+		m_vertBuff.bindVertexBuffer(data.m_jobs, 
+			1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 4, 7);
 
 
-	// Alpha
-	m_vertBuff.bindVertexBuffer(data.m_jobs, 
-		1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 4, 7);
+		data.m_jobs.drawArrays(GL_POINTS, 
+			m_aliveParticlesCount,
+			data.m_subMeshIndicesCount);
+	}
 
 
-	data.m_jobs.drawArrays(GL_POINTS, 
-		m_aliveParticlesCount,
-		data.m_subMeshIndicesCount);
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -315,15 +358,17 @@ const Material& ParticleEmitter::getMaterial()
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::onMoveComponentUpdate(
+Error ParticleEmitter::onMoveComponentUpdate(
 	SceneNode& node, F32 prevTime, F32 crntTime)
 	SceneNode& node, F32 prevTime, F32 crntTime)
 {
 {
 	m_identityRotation =
 	m_identityRotation =
 		getWorldTransform().getRotation() == Mat3x4::getIdentity();
 		getWorldTransform().getRotation() == Mat3x4::getIdentity();
+
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::createParticlesSimulation(SceneGraph* scene)
+Error ParticleEmitter::createParticlesSimulation(SceneGraph* scene)
 {
 {
 #if 0
 #if 0
 	collShape = getSceneAllocator().newInstance<btSphereShape>(particle.size);
 	collShape = getSceneAllocator().newInstance<btSphereShape>(particle.size);
@@ -349,28 +394,44 @@ void ParticleEmitter::createParticlesSimulation(SceneGraph* scene)
 		particles.push_back(part);
 		particles.push_back(part);
 	}
 	}
 #endif
 #endif
+	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::createParticlesSimpleSimulation(SceneGraph* scene)
+Error ParticleEmitter::createParticlesSimpleSimulation()
 {
 {
-	m_particles.resize(m_maxNumOfParticles);
+	Error err = m_particles.create(getSceneAllocator(), m_maxNumOfParticles);
+	if(err)
+	{
+		return err;
+	}
 
 
 	for(U i = 0; i < m_maxNumOfParticles; i++)
 	for(U i = 0; i < m_maxNumOfParticles; i++)
 	{
 	{
 		ParticleSimple* part = 
 		ParticleSimple* part = 
 			getSceneAllocator().newInstance<ParticleSimple>();
 			getSceneAllocator().newInstance<ParticleSimple>();
 
 
-		part->m_size = getRandom(m_particle.m_size, m_particle.m_sizeDeviation);
-		part->m_alpha = 
-			getRandom(m_particle.m_alpha, m_particle.m_alphaDeviation);
+		if(part)
+		{
+			part->m_size = 
+				getRandom(m_particle.m_size, m_particle.m_sizeDeviation);
+			part->m_alpha = 
+				getRandom(m_particle.m_alpha, m_particle.m_alphaDeviation);
 
 
-		m_particles[i] = part;
+			m_particles[i] = part;
+		}
+		else
+		{
+			err = ErrorCode::OUT_OF_MEMORY;
+			break;
+		}
 	}
 	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 {
 {
 	// - Deactivate the dead particles
 	// - Deactivate the dead particles
 	// - Calc the AABB
 	// - Calc the AABB
@@ -489,25 +550,37 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 	}
 	}
 
 
 	// Do something more
 	// Do something more
-	doInstancingCalcs();
+	return doInstancingCalcs();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void ParticleEmitter::doInstancingCalcs()
+Error ParticleEmitter::doInstancingCalcs()
 {
 {
+	Error err = ErrorCode::NONE;
+
+	//
 	// Gather the move components of the instances
 	// Gather the move components of the instances
-	SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
+	//
+	SceneFrameDArray<MoveComponent*> instanceMoves;
+	U instanceMovesCount = 0;
 	Timestamp instancesTimestamp = 0;
 	Timestamp instancesTimestamp = 0;
-	SceneObject::visitChildren([&](SceneObject& obj) -> Error
+
+	err = instanceMoves.create(getSceneFrameAllocator(), 64);
+	if(err)
+	{
+		return err;
+	}
+
+	err = SceneObject::visitChildren([&](SceneObject& obj) -> Error
 	{	
 	{	
-		if(obj.getType() == SceneObject::Type::SCENE_NODE)
+		if(obj.getType() == SceneNode::getClassType())
 		{
 		{
 			SceneNode& sn = obj.downCast<SceneNode>();
 			SceneNode& sn = obj.downCast<SceneNode>();
 			if(sn.tryGetComponent<InstanceComponent>())
 			if(sn.tryGetComponent<InstanceComponent>())
 			{
 			{
 				MoveComponent& move = sn.getComponent<MoveComponent>();
 				MoveComponent& move = sn.getComponent<MoveComponent>();
 
 
-				instanceMoves.push_back(&move);
+				instanceMoves[instanceMovesCount++] = &move;
 
 
 				instancesTimestamp = 
 				instancesTimestamp = 
 					std::max(instancesTimestamp, move.getTimestamp());
 					std::max(instancesTimestamp, move.getTimestamp());
@@ -517,30 +590,42 @@ void ParticleEmitter::doInstancingCalcs()
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
 	});
 	});
 
 
+	//
 	// If instancing
 	// If instancing
-	if(instanceMoves.size() != 0)
+	//
+	if(instanceMovesCount > 0)
 	{
 	{
 		Bool transformsNeedUpdate = false;
 		Bool transformsNeedUpdate = false;
 
 
 		// Check if an instance was added or removed and reset the spatials and
 		// Check if an instance was added or removed and reset the spatials and
 		// the transforms
 		// the transforms
-		if(instanceMoves.size() != m_transforms.size())
+		if(instanceMovesCount != m_transforms.getSize())
 		{
 		{
 			transformsNeedUpdate = true;
 			transformsNeedUpdate = true;
 
 
 			// Check if instances added or removed
 			// Check if instances added or removed
-			if(m_transforms.size() < instanceMoves.size())
+			if(m_transforms.getSize() < instanceMovesCount)
 			{
 			{
 				// Instances added
 				// Instances added
 
 
-				U diff = instanceMoves.size() - m_transforms.size();
+				U diff = instanceMovesCount - m_transforms.getSize();
 
 
 				while(diff-- != 0)
 				while(diff-- != 0)
 				{
 				{
 					ObbSpatialComponent* newSpatial = getSceneAllocator().
 					ObbSpatialComponent* newSpatial = getSceneAllocator().
 						newInstance<ObbSpatialComponent>(this);
 						newInstance<ObbSpatialComponent>(this);
 
 
-					addComponent(newSpatial);
+					if(newSpatial == nullptr)
+					{
+						err = ErrorCode::OUT_OF_MEMORY;
+						break;
+					}
+
+					err = addComponent(newSpatial);
+					if(err)
+					{
+						break;
+					}
 				}
 				}
 			}
 			}
 			else
 			else
@@ -551,42 +636,61 @@ void ParticleEmitter::doInstancingCalcs()
 				ANKI_ASSERT(0 && "TODO");
 				ANKI_ASSERT(0 && "TODO");
 			}
 			}
 
 
-			m_transforms.resize(instanceMoves.size());
+			err = m_transforms.resize(getSceneAllocator(), instanceMovesCount);
 		}
 		}
 
 
-		if(transformsNeedUpdate || m_transformsTimestamp < instancesTimestamp)
+		if(!err && (transformsNeedUpdate 
+			|| m_transformsTimestamp < instancesTimestamp))
 		{
 		{
 			m_transformsTimestamp = instancesTimestamp;
 			m_transformsTimestamp = instancesTimestamp;
 
 
 			// Update the transforms
 			// Update the transforms
-			for(U i = 0; i < instanceMoves.size(); i++)
+			for(U i = 0; i < instanceMovesCount; i++)
 			{
 			{
 				m_transforms[i] = instanceMoves[i]->getWorldTransform();
 				m_transforms[i] = instanceMoves[i]->getWorldTransform();
 			}
 			}
 		}
 		}
 
 
 		// Update the spatials anyway
 		// Update the spatials anyway
-		U count = 0;
-		iterateComponentsOfType<SpatialComponent>([&](SpatialComponent& sp)
+		if(!err)
 		{
 		{
-			// Skip the first
-			if(count != 0)	
+			U count = 0;
+			err = iterateComponentsOfType<SpatialComponent>(
+				[&](SpatialComponent& sp) -> Error
 			{
 			{
-				ObbSpatialComponent* msp = 
-					staticCastPtr<ObbSpatialComponent*>(&sp);
-		
-				Obb aobb = m_obb;
-				aobb.setCenter(Vec4(0.0));
-				msp->m_obb = aobb.getTransformed(m_transforms[count - 1]);
-
-				msp->markForUpdate();
-			}
+				Error err2 = ErrorCode::NONE;
+
+				// Skip the first
+				if(count != 0)	
+				{
+					ObbSpatialComponent* msp = 
+						staticCastPtr<ObbSpatialComponent*>(&sp);
+
+					if(msp)
+					{
+						Obb aobb = m_obb;
+						aobb.setCenter(Vec4(0.0));
+						msp->m_obb =
+							aobb.getTransformed(m_transforms[count - 1]);
+
+						msp->markForUpdate();
+					}
+					else
+					{
+						err2 = ErrorCode::OUT_OF_MEMORY;
+					}
+				}
+
+				++count;
 
 
-			++count;
-		});
+				return err2;
+			});
 
 
-		ANKI_ASSERT(count - 1 == m_transforms.size());
+			ANKI_ASSERT(count - 1 == m_transforms.getSize());
+		}
 	} // end if instancing
 	} // end if instancing
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -598,7 +702,7 @@ Bool ParticleEmitter::getHasWorldTransforms()
 //==============================================================================
 //==============================================================================
 void ParticleEmitter::getRenderWorldTransform(U index, Transform& trf)
 void ParticleEmitter::getRenderWorldTransform(U index, Transform& trf)
 {
 {
-	ANKI_ASSERT(m_transforms.size() > 0);
+	ANKI_ASSERT(m_transforms.getSize() > 0);
 
 
 	if(index == 0)
 	if(index == 0)
 	{
 	{
@@ -609,7 +713,7 @@ void ParticleEmitter::getRenderWorldTransform(U index, Transform& trf)
 	else
 	else
 	{
 	{
 		--index;
 		--index;
-		ANKI_ASSERT(index < m_transforms.size());
+		ANKI_ASSERT(index < m_transforms.getSize());
 
 
 		// The particle positions are already in word space. Move them back to
 		// The particle positions are already in word space. Move them back to
 		// local space
 		// local space

+ 104 - 59
src/scene/SceneGraph.cpp

@@ -28,44 +28,66 @@ public:
 	F32 m_prevUpdateTime;
 	F32 m_prevUpdateTime;
 	F32 m_crntTime;
 	F32 m_crntTime;
 
 
-	void operator()(U32 taskId, PtrSize threadsCount)
+	Error operator()(U32 taskId, PtrSize threadsCount)
 	{
 	{
 		PtrSize start, end;
 		PtrSize start, end;
 		choseStartEnd(
 		choseStartEnd(
 			taskId, threadsCount, m_scene->getSceneNodesCount(), start, end);
 			taskId, threadsCount, m_scene->getSceneNodesCount(), start, end);
 
 
 		// Start with the root nodes
 		// Start with the root nodes
-		m_scene->iterateSceneNodes(start, end, [&](SceneNode& node)
+		Error err = m_scene->iterateSceneNodes(
+			start, end, [&](SceneNode& node) -> Error
 		{
 		{
+			Error err = ErrorCode::NONE;
 			if(node.getParent() == nullptr)
 			if(node.getParent() == nullptr)
 			{
 			{
-				updateInternal(node, m_prevUpdateTime, m_crntTime);
+				err = updateInternal(node, m_prevUpdateTime, m_crntTime);
 			}
 			}
+
+			return err;
 		});
 		});
+
+		return err;
 	}
 	}
 
 
-	void updateInternal(SceneNode& node, F32 prevTime, F32 crntTime)
+	ANKI_USE_RESULT Error updateInternal(
+		SceneNode& node, F32 prevTime, F32 crntTime)
 	{
 	{
+		Error err = ErrorCode::NONE;
+
 		// Components update
 		// Components update
-		node.iterateComponents([&](SceneComponent& comp)
+		err = node.iterateComponents([&](SceneComponent& comp) -> Error
 		{
 		{
-			comp.updateReal(node, prevTime, crntTime);
+			Bool updated = false;
+			return comp.updateReal(node, prevTime, crntTime, updated);
 		});
 		});
 
 
+		if(err)
+		{
+			return err;
+		}
+
 		// Update children
 		// Update children
-		node.visitChildren([&](SceneObject& obj) -> Error
+		err = node.visitChildren([&](SceneObject& obj) -> Error
 		{
 		{
+			Error err2 = ErrorCode::NONE;
+
 			if(obj.getType() == SceneObject::Type::SCENE_NODE)
 			if(obj.getType() == SceneObject::Type::SCENE_NODE)
 			{
 			{
 				SceneNode& child = obj.downCast<SceneNode>();
 				SceneNode& child = obj.downCast<SceneNode>();
-				updateInternal(child, prevTime, crntTime);
+				err2 = updateInternal(child, prevTime, crntTime);
 			}
 			}
 
 
-			return ErrorCode::NONE;
+			return err2;
 		});
 		});
 
 
 		// Frame update
 		// Frame update
-		node.frameUpdate(prevTime, crntTime);
+		if(!err)
+		{
+			err = node.frameUpdate(prevTime, crntTime);
+		}
+
+		return err;
 	}
 	}
 };
 };
 
 
@@ -76,50 +98,63 @@ public:
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-SceneGraph::SceneGraph(AllocAlignedCallback allocCb, void* allocCbData, 
-	Threadpool* threadpool, ResourceManager* resources)
-:	m_threadpool(threadpool),
-	m_resources(resources),
-	m_gl(&m_resources->_getGlDevice()),
-	m_alloc(allocCb, allocCbData, ANKI_SCENE_ALLOCATOR_SIZE),
-	m_frameAlloc(allocCb, allocCbData, ANKI_SCENE_FRAME_ALLOCATOR_SIZE),
-	m_nodes(m_alloc),
-	m_dict(10, DictionaryHasher(), DictionaryEqual(), m_alloc),
-	m_physics(),
+SceneGraph::SceneGraph()
+:	m_physics(),
 	m_sectorGroup(this),
 	m_sectorGroup(this),
 	m_events(this)
 	m_events(this)
-{
-	m_nodes.reserve(ANKI_SCENE_OPTIMAL_SCENE_NODES_COUNT);
-
-	m_objectsMarkedForDeletionCount.store(0);
-
-	m_ambientCol = Vec3(0.0);
-}
+{}
 
 
 //==============================================================================
 //==============================================================================
 SceneGraph::~SceneGraph()
 SceneGraph::~SceneGraph()
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
-void SceneGraph::registerNode(SceneNode* node)
+Error SceneGraph::create(
+	AllocAlignedCallback allocCb, 
+	void* allocCbData, 
+	Threadpool* threadpool, 
+	ResourceManager* resources)
+{
+	m_threadpool = threadpool;
+	m_resources = resources;
+	m_objectsMarkedForDeletionCount.store(0);
+	m_ambientCol = Vec3(0.0);
+	m_gl = &m_resources->_getGlDevice();
+
+	m_alloc = SceneAllocator<U8>(
+		allocCb, allocCbData, ANKI_SCENE_ALLOCATOR_SIZE);
+	m_frameAlloc = SceneFrameAllocator<U8>(
+		allocCb, allocCbData, ANKI_SCENE_FRAME_ALLOCATOR_SIZE);
+
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+Error SceneGraph::registerNode(SceneNode* node)
 {
 {
 	ANKI_ASSERT(node);
 	ANKI_ASSERT(node);
 
 
 	// Add to dict if it has name
 	// Add to dict if it has name
 	if(node->getName())
 	if(node->getName())
 	{
 	{
-		if(m_dict.find(node->getName()) != m_dict.end())
+		if(tryFindSceneNode(node->getName()))
 		{
 		{
-			throw ANKI_EXCEPTION("Node with the same name already exists");
+			ANKI_LOGE("Node with the same name already exists");
+			return ErrorCode::FUNCTION_FAILED;
 		}
 		}
 
 
-		m_dict[node->getName()] = node;
+		//m_dict[node->getName()] = node;
 	}
 	}
 
 
 	// Add to vector
 	// Add to vector
-	ANKI_ASSERT(
-		std::find(m_nodes.begin(), m_nodes.end(), node) == m_nodes.end());
-	m_nodes.push_back(node);
+	Error err = m_nodes.pushBack(m_alloc, node);
+
+	if(!err)
+	{
+		++m_nodesCount;
+	}
+
+	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -136,9 +171,12 @@ void SceneGraph::unregisterNode(SceneNode* node)
 	}
 	}
 	
 	
 	ANKI_ASSERT(it != m_nodes.end());
 	ANKI_ASSERT(it != m_nodes.end());
-	m_nodes.erase(it);
+	m_nodes.erase(m_alloc, it);
+
+	--m_nodesCount;
 
 
 	// Remove from dict
 	// Remove from dict
+#if 0
 	if(node->getName())
 	if(node->getName())
 	{
 	{
 		auto it = m_dict.find(node->getName());
 		auto it = m_dict.find(node->getName());
@@ -146,60 +184,62 @@ void SceneGraph::unregisterNode(SceneNode* node)
 		ANKI_ASSERT(it != m_dict.end());
 		ANKI_ASSERT(it != m_dict.end());
 		m_dict.erase(it);
 		m_dict.erase(it);
 	}
 	}
+#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-SceneNode& SceneGraph::findSceneNode(const char* name)
+SceneNode& SceneGraph::findSceneNode(const CString& name)
 {
 {
-	ANKI_ASSERT(m_dict.find(name) != m_dict.end());
-	return *(m_dict.find(name))->second;
+	SceneNode* node = tryFindSceneNode(name);
+	ANKI_ASSERT(node);
+	return *node;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-SceneNode* SceneGraph::tryFindSceneNode(const char* name)
+SceneNode* SceneGraph::tryFindSceneNode(const CString& name)
 {
 {
-	auto it = m_dict.find(name);
-	return (it == m_dict.end()) ? nullptr : it->second;
+	auto it = m_nodes.getBegin();
+	for(; it != m_nodes.getEnd(); ++it)
+	{
+		if((*it)->getName() == name)
+		{
+			break;
+		}
+	}
+
+	return (it == m_nodes.getEnd()) ? nullptr : (*it);
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void SceneGraph::deleteNodesMarkedForDeletion()
 void SceneGraph::deleteNodesMarkedForDeletion()
 {
 {
-	SceneAllocator<SceneNode> al = m_alloc;
-
 	/// Delete all nodes pending deletion. At this point all scene threads 
 	/// Delete all nodes pending deletion. At this point all scene threads 
 	/// should have finished their tasks
 	/// should have finished their tasks
 	while(m_objectsMarkedForDeletionCount > 0)
 	while(m_objectsMarkedForDeletionCount > 0)
 	{
 	{
-		// First gather the nodes that will be deleted
-		SceneFrameVector<decltype(m_nodes)::iterator> forDeletion;
-		for(auto it = m_nodes.begin(); it != m_nodes.end(); it++)
+		auto it = m_nodes.begin();
+		for(; it != m_nodes.end(); it++)
 		{
 		{
 			if((*it)->isMarkedForDeletion())
 			if((*it)->isMarkedForDeletion())
 			{
 			{
-				forDeletion.push_back(it);
+				// Delete node
+				unregisterNode(*it);
+				m_alloc.deleteInstance(*it);		
 			}
 			}
 		}
 		}
 
 
-		// Now delete nodes
-		for(auto& it : forDeletion)
-		{
-			// Remove it
-			unregisterNode(*it);
-
-			m_alloc.deleteInstance(*it);
-		}
-
 		// Do the same for events
 		// Do the same for events
 		m_events.deleteEventsMarkedForDeletion();
 		m_events.deleteEventsMarkedForDeletion();
 	}
 	}
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void SceneGraph::update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer)
+Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer)
 {
 {
 	ANKI_ASSERT(m_mainCam);
 	ANKI_ASSERT(m_mainCam);
 
 
+	Error err = ErrorCode::NONE;
+
 	ANKI_COUNTER_START_TIMER(SCENE_UPDATE_TIME);
 	ANKI_COUNTER_START_TIMER(SCENE_UPDATE_TIME);
 
 
 	//
 	//
@@ -234,11 +274,16 @@ void SceneGraph::update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer)
 		threadPool.assignNewTask(i, &job);
 		threadPool.assignNewTask(i, &job);
 	}
 	}
 
 
-	threadPool.waitForAllThreadsToFinish();
+	err = threadPool.waitForAllThreadsToFinish();
 
 
-	doVisibilityTests(*m_mainCam, *this, renderer);
+	if(!err)
+	{
+		err = doVisibilityTests(*m_mainCam, *this, renderer);
+	}
 
 
 	ANKI_COUNTER_STOP_TIMER_INC(SCENE_UPDATE_TIME);
 	ANKI_COUNTER_STOP_TIMER_INC(SCENE_UPDATE_TIME);
+
+	return err;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 13 - 12
src/script/LuaBinder.cpp

@@ -27,12 +27,14 @@ void checkArgsCount(lua_State* l, I argsCount)
 //==============================================================================
 //==============================================================================
 void createClass(lua_State* l, const char* className)
 void createClass(lua_State* l, const char* className)
 {
 {
-	lua_newtable(l);
-	lua_setglobal(l, className);
-	luaL_newmetatable(l, className);
-	lua_pushstring(l, "__index");
-	lua_pushvalue(l, -2);  // pushes the metatable
-	lua_settable(l, -3);  // metatable.__index = metatable
+	lua_newtable(l); // push new table
+	lua_setglobal(l, className); // pop and make global
+	luaL_newmetatable(l, className); // push
+	lua_pushstring(l, "__index"); // push
+	lua_pushvalue(l, -2);  // pushes copy of the metatable
+	lua_settable(l, -3);  // pop*2: metatable.__index = metatable
+
+	// After all these the metatable is in the top of tha stack
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -47,10 +49,10 @@ void pushCFunctionMethod(lua_State* l, const char* name, lua_CFunction luafunc)
 void pushCFunctionStatic(lua_State* l, const char* className,
 void pushCFunctionStatic(lua_State* l, const char* className,
 	const char* name, lua_CFunction luafunc) 
 	const char* name, lua_CFunction luafunc) 
 {
 {
-	lua_getglobal(l, className);
-	lua_pushcfunction(l, luafunc);
-	lua_setfield(l, -2, name);
-	lua_pop(l, 1);
+	lua_getglobal(l, className); // push
+	lua_pushcfunction(l, luafunc); // push
+	lua_setfield(l, -2, name); // pop global
+	lua_pop(l, 1); // pop cfunc
 }
 }
 
 
 } // end namespace lua_detail
 } // end namespace lua_detail
@@ -132,9 +134,8 @@ void LuaBinder::evalString(const CString& str)
 	int e = luaL_dostring(m_l, &str[0]);
 	int e = luaL_dostring(m_l, &str[0]);
 	if(e)
 	if(e)
 	{
 	{
-		String str(lua_tostring(m_l, -1), m_alloc);
+		ANKI_LOGE("%s", lua_tostring(m_l, -1));
 		lua_pop(m_l, 1);
 		lua_pop(m_l, 1);
-		throw ANKI_EXCEPTION("%s", &str[0]);
 	}
 	}
 }
 }
 
 

+ 8 - 0
src/script/Util.cpp

@@ -16,4 +16,12 @@ ANKI_SCRIPT_WRAP(CString)
 	ANKI_LUA_CLASS_END()
 	ANKI_LUA_CLASS_END()
 }
 }
 
 
+//==============================================================================
+ANKI_SCRIPT_WRAP(Error)
+{
+	ANKI_LUA_CLASS_BEGIN(lb, Error)
+		ANKI_LUA_CONSTRUCTOR(I)
+	ANKI_LUA_CLASS_END()
+}
+
 } // end namespace anki
 } // end namespace anki

+ 1 - 1
src/util/Memory.cpp

@@ -890,7 +890,7 @@ public:
 			}
 			}
 			else
 			else
 			{
 			{
-				destroy(chunk);
+				destruct(chunk);
 				m_allocCb(m_allocCbUserData, chunk, 0, 0);
 				m_allocCb(m_allocCbUserData, chunk, 0, 0);
 				chunk = nullptr;
 				chunk = nullptr;
 			}
 			}