Pārlūkot izejas kodu

UBOs on MS are slower than plain uniforms. Keeping both options with uniforms the default. Rework on the Tiler, moving to another class for fine opts and broader purpose

Panagiotis Christopoulos Charitos 13 gadi atpakaļ
vecāks
revīzija
9b7951e7a9

+ 5 - 1
CMakeLists.txt

@@ -74,7 +74,11 @@ MESSAGE("++ AnKi window backend: ${ANKI_WINDOW_BACKEND}")
 # Build type
 # Build type
 IF(CMAKE_BUILD_TYPE STREQUAL Debug)
 IF(CMAKE_BUILD_TYPE STREQUAL Debug)
 ELSE()
 ELSE()
-	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ")
+	SET(FLAGS "-s -flto ")
+
+	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
+	SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
+	SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
 ENDIF()
 ENDIF()
 
 
 #
 #

+ 1 - 1
include/anki/Config.h.cmake

@@ -29,7 +29,7 @@
 #	define ANKI_DEBUG 1
 #	define ANKI_DEBUG 1
 #endif
 #endif
 
 
-#define ANKI_FILE __BASE_FILE__
+#define ANKI_FILE __FILE__
 #define ANKI_FUNC __func__
 #define ANKI_FUNC __func__
 
 
 #endif
 #endif

+ 2 - 2
include/anki/gl/ShaderProgram.h

@@ -266,11 +266,11 @@ public:
 		return name;
 		return name;
 	}
 	}
 
 
-	GLuint getBindingPoint() const
+	GLuint getBinding() const
 	{
 	{
 		return bindingPoint;
 		return bindingPoint;
 	}
 	}
-	void setBindingPoint(GLuint bp) const
+	void setBinding(GLuint bp) const
 	{
 	{
 		// Don't try any opts with existing binding point. Binding points 
 		// Don't try any opts with existing binding point. Binding points 
 		// should break
 		// should break

+ 1 - 1
include/anki/renderer/Dbg.h

@@ -4,7 +4,7 @@
 #include "anki/renderer/RenderingPass.h"
 #include "anki/renderer/RenderingPass.h"
 #include "anki/gl/Fbo.h"
 #include "anki/gl/Fbo.h"
 #include <memory>
 #include <memory>
-#include "anki/renderer/Drawer.h"
+#include "anki/renderer/DebugDrawer.h"
 
 
 namespace anki {
 namespace anki {
 
 

+ 10 - 5
include/anki/renderer/Drawer.h

@@ -1,24 +1,31 @@
 #ifndef ANKI_RENDERER_DRAWER_H
 #ifndef ANKI_RENDERER_DRAWER_H
 #define ANKI_RENDERER_DRAWER_H
 #define ANKI_RENDERER_DRAWER_H
 
 
-#include "anki/resource/Resource.h"
-#include "anki/scene/SceneNode.h"
+#include "anki/util/StdTypes.h"
 
 
 namespace anki {
 namespace anki {
 
 
 class PassLevelKey;
 class PassLevelKey;
+class Renderer;
+class Frustumable;
+class Renderable;
 
 
 /// It includes all the functions to render a Renderable
 /// It includes all the functions to render a Renderable
 class RenderableDrawer
 class RenderableDrawer
 {
 {
 public:
 public:
+	static const U UNIFORM_BLOCK_MAX_SIZE = 256;
+
 	/// The one and only constructor
 	/// The one and only constructor
 	RenderableDrawer(Renderer* r_)
 	RenderableDrawer(Renderer* r_)
 		: r(r_)
 		: r(r_)
 	{}
 	{}
 
 
+	void prepareDraw()
+	{}
+
 	void render(const Frustumable& fr,
 	void render(const Frustumable& fr,
-		uint pass, Renderable& renderable);
+		U32 pass, Renderable& renderable);
 
 
 private:
 private:
 	Renderer* r;
 	Renderer* r;
@@ -27,8 +34,6 @@ private:
 		const PassLevelKey& key,
 		const PassLevelKey& key,
 		const Frustumable& fr,
 		const Frustumable& fr,
 		Renderable& renderable);
 		Renderable& renderable);
-
-	void setBuildinIds(Renderable& renderable);
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

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

@@ -12,6 +12,7 @@
 #include "anki/renderer/Pps.h"
 #include "anki/renderer/Pps.h"
 #include "anki/renderer/Bs.h"
 #include "anki/renderer/Bs.h"
 #include "anki/renderer/Dbg.h"
 #include "anki/renderer/Dbg.h"
+#include "anki/renderer/Tiler.h"
 #include "anki/renderer/Drawer.h"
 #include "anki/renderer/Drawer.h"
 
 
 namespace anki {
 namespace anki {
@@ -137,6 +138,15 @@ public:
 		return is;
 		return is;
 	}
 	}
 
 
+	const Tiler& getTiler() const
+	{
+		return tiler;
+	}
+	Tiler& getTiler()
+	{
+		return tiler;
+	}
+
 	const Pps& getPps() const
 	const Pps& getPps() const
 	{
 	{
 		return pps;
 		return pps;
@@ -268,6 +278,8 @@ protected:
 	Bs bs; ///< Blending stage
 	Bs bs; ///< Blending stage
 	/// @}
 	/// @}
 
 
+	Tiler tiler;
+
 	/// Width of the rendering. Don't confuse with the window width
 	/// Width of the rendering. Don't confuse with the window width
 	U width;
 	U width;
 	/// Height of the rendering. Don't confuse with the window width
 	/// Height of the rendering. Don't confuse with the window width

+ 85 - 0
include/anki/renderer/Tiler.h

@@ -0,0 +1,85 @@
+#ifndef ANKI_RENDERER_TILER_H
+#define ANKI_RENDERER_TILER_H
+
+#include "anki/util/StdTypes.h"
+#include "anki/collision/Collision.h"
+#include "anki/gl/Fbo.h"
+#include "anki/gl/Texture.h"
+#include "anki/resource/Resource.h"
+#include "anki/core/Timestamp.h"
+
+namespace anki {
+
+class Renderer;
+class Camera;
+
+/// Tiler used for visibility tests
+class Tiler
+{
+	friend struct UpdateTiles2PlanesJob;
+	friend struct UpdateTiles4PlanesPerspectiveCameraJob;
+
+public:
+	// Config. These values affect the size of the uniform blocks and keep in
+	// mind that there are size limitations in uniform blocks.
+	static const U TILES_X_COUNT = 16;
+	static const U TILES_Y_COUNT = 16;
+
+	Tiler();
+	~Tiler();
+
+	void init(Renderer* r);
+
+	/// Update the tiles before doing visibility tests
+	void updateTiles(Camera& cam, const Texture& depthMap);
+
+	/// Return true if the cs is in at least one shape. If the tileIds is not 
+	/// nullptr then check all tiles and return the IDS if the tiles that the
+	/// cs is on
+	Bool test(const CollisionShape& cs,
+		Array<U32, TILES_X_COUNT * TILES_Y_COUNT>* tileIds = nullptr) const;
+
+private:
+	/// A screen tile
+	struct Tile
+	{
+		/// @name Frustum planes
+		/// @{
+		Array<Plane, Frustum::FP_COUNT> planes; ///< In local space
+		Array<Plane, Frustum::FP_COUNT> planesWSpace; ///< In world space
+		/// @}
+	};
+
+	/// @note The [0][0] is the bottom left tile
+	union
+	{
+		Array<Array<Tile, TILES_X_COUNT>, TILES_Y_COUNT> tiles;
+		Array<Tile, TILES_X_COUNT * TILES_Y_COUNT> tiles1d;
+	};
+
+	/// The timestamp of the 4 planes update
+	U32 planes4UpdateTimestamp = Timestamp::getTimestamp();
+
+	/// A texture of TILES_X_COUNT*TILES_Y_COUNT size and format XXX. Used to
+	/// calculate the near and far planes of the tiles
+	Texture fai;
+
+	/// Main FBO
+	Fbo fbo;
+
+	/// Main shader program
+	ShaderProgramResourcePointer prog;
+
+	Renderer* r;
+	const Camera* prevCam;
+
+	void initInternal(Renderer* r);
+
+	void update4Planes(Camera& cam);
+	void update2Planes(Camera& cam, 
+		F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2]);
+};
+
+} // end namespace anki
+
+#endif

+ 1 - 1
include/anki/scene/Property.h

@@ -387,6 +387,6 @@ private:
 	NameToPropertyMap map;
 	NameToPropertyMap map;
 };
 };
 
 
-} // namespace anki
+} // end namespace anki
 
 
 #endif
 #endif

+ 29 - 27
include/anki/scene/Renderable.h

@@ -4,60 +4,62 @@
 #include "anki/scene/Property.h"
 #include "anki/scene/Property.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Vector.h"
 #include "anki/gl/Ubo.h"
 #include "anki/gl/Ubo.h"
+#include "anki/resource/Material.h"
 
 
 namespace anki {
 namespace anki {
 
 
 class ModelPatchBase;
 class ModelPatchBase;
-class Material;
-class MaterialVariable;
 class Transform;
 class Transform;
 
 
 /// @addtogroup Scene
 /// @addtogroup Scene
 /// @{
 /// @{
 
 
-/// Material variable property. Its a layer on top of material variables
-template<typename T>
-class MaterialVariableProperty: public ReadCowPointerProperty<T>
+/// XXX
+enum BuildinMaterialVariableId
 {
 {
-public:
-	typedef T Value;
-	typedef ReadCowPointerProperty<T> Base;
+	BMV_NO_BUILDIN = 0,
+	BMV_MODEL_VIEW_PROJECTION_MATRIX,
+	BMV_MODEL_VIEW_MATRIX,
+	BMV_NORMAL_MATRIX,
+	BMV_BLURRING,
+	BMV_COUNT
+};
 
 
-	/// @name Constructors/Destructor
-	/// @{
-	MaterialVariableProperty(const char* name, const Value* x,
-		const MaterialVariable* mvar_)
-		: Base(name, x), mvar(mvar_)
-	{}
-	/// @}
+/// A wrapper on top of MaterialVariable
+class RenderableMaterialVariable
+{
+public:
+	RenderableMaterialVariable(const MaterialVariable* mvar_);
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
-	U32 getBuildinId() const
+	BuildinMaterialVariableId getBuildinId() const
 	{
 	{
 		return buildinId;
 		return buildinId;
 	}
 	}
-	void setBuildinId(U32 id)
-	{
-		buildinId = id;
-	}
 
 
 	const MaterialVariable& getMaterialVariable() const
 	const MaterialVariable& getMaterialVariable() const
 	{
 	{
 		return *mvar;
 		return *mvar;
 	}
 	}
+
+	const std::string& getName() const
+	{
+		return mvar->getName();
+	}
 	/// @}
 	/// @}
 
 
 private:
 private:
-	U32 buildinId = 0; ///< The renderer sets it
+	BuildinMaterialVariableId buildinId;
 	const MaterialVariable* mvar = nullptr;
 	const MaterialVariable* mvar = nullptr;
+	PropertyBase* prop = nullptr;
 };
 };
 
 
 /// Renderable interface. Implemented by renderable scene nodes
 /// Renderable interface. Implemented by renderable scene nodes
 class Renderable
 class Renderable
 {
 {
 public:
 public:
-	typedef Vector<PropertyBase*> MaterialVariableProperties;
+	typedef PtrVector<RenderableMaterialVariable> RenderableMaterialVariables;
 
 
 	Renderable()
 	Renderable()
 	{}
 	{}
@@ -78,13 +80,13 @@ public:
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
-	MaterialVariableProperties::iterator getPropertiesBegin()
+	RenderableMaterialVariables::iterator getVariablesBegin()
 	{
 	{
-		return props.begin();
+		return vars.begin();
 	}
 	}
-	MaterialVariableProperties::iterator getPropertiesEnd()
+	RenderableMaterialVariables::iterator getVariablesEnd()
 	{
 	{
-		return props.end();
+		return vars.end();
 	}
 	}
 
 
 	Ubo& getUbo()
 	Ubo& getUbo()
@@ -97,7 +99,7 @@ protected:
 	void init(PropertyMap& pmap);
 	void init(PropertyMap& pmap);
 
 
 private:
 private:
-	MaterialVariableProperties props;
+	RenderableMaterialVariables vars;
 	Ubo ubo;
 	Ubo ubo;
 };
 };
 /// @}
 /// @}

+ 3 - 1
shaders/Final.glsl

@@ -17,6 +17,8 @@ void main()
 	vec3 col = texture2D(rasterImage, vTexCoords).rgb;
 	vec3 col = texture2D(rasterImage, vTexCoords).rgb;
 	fFragColor = col;
 	fFragColor = col;
 #else
 #else
-	fFragColor = vec3(texture2D(rasterImage, vTexCoords).r);
+	uvec2 msAll = texture2D(rasterImage, vTexCoords).rg;
+	vec4 diffuseAndSpec = unpackUnorm4x8(msAll[0]);
+	fFragColor = vec3(diffuseAndSpec.rgb);
 #endif
 #endif
 }
 }

+ 16 - 0
src/collision/Sphere.cpp

@@ -10,6 +10,7 @@ F32 Sphere::testPlane(const Plane& p) const
 	const Sphere& s = *this;
 	const Sphere& s = *this;
 	F32 dist = p.test(s.getCenter());
 	F32 dist = p.test(s.getCenter());
 
 
+#if 0
 	if(dist > s.getRadius())
 	if(dist > s.getRadius())
 	{
 	{
 		return dist - s.getRadius();
 		return dist - s.getRadius();
@@ -22,6 +23,21 @@ F32 Sphere::testPlane(const Plane& p) const
 	{
 	{
 		return 0.0;
 		return 0.0;
 	}
 	}
+#else
+	F32 opt = dist - s.getRadius();
+	if(opt > 0)
+	{
+		return opt;
+	}
+	else if((opt = dist + s.getRadius()) < 0)
+	{
+		return opt;
+	}
+	else
+	{
+		return 0.0;
+	}
+#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 53 - 115
src/renderer/Drawer.cpp

@@ -11,64 +11,6 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-enum BuildinId
-{
-	BI_UNITIALIZED = 0,
-	BT_NO_BUILDIN,
-	BI_MODEL_VIEW_PROJECTION_MATRIX,
-	BI_MODEL_VIEW_MATRIX,
-	BI_NORMAL_MATRIX,
-	BI_BLURRING,
-	BI_COUNT
-};
-
-static Array<const char*, BI_COUNT - 2> buildinNames = {{
-	"modelViewProjectionMat",
-	"modelViewMat",
-	"normalMat",
-	"blurring"
-}};
-
-struct SetBuildinIdVisitor
-{
-	Bool setted;
-
-	template<typename TProp>
-	void visit(TProp& x)
-	{
-		MaterialVariableProperty<typename TProp::Value>& mprop =
-			static_cast<MaterialVariableProperty<typename TProp::Value>&>(x);
-
-		const MaterialVariable& mv = mprop.getMaterialVariable();
-
-		if(mprop.getBuildinId() == BI_UNITIALIZED)
-		{
-			const std::string& name = mv.getName();
-
-			for(U i = 0; i < buildinNames.size(); i++)
-			{
-				if(name == buildinNames[i])
-				{
-					mprop.setBuildinId(i + 2);
-					break;
-				}
-			}
-
-			if(mprop.getBuildinId() == BI_UNITIALIZED)
-			{
-				mprop.setBuildinId(BT_NO_BUILDIN);
-			}
-
-			setted = true;
-		}
-
-		setted = false
-	}
-};
-
-//==============================================================================
-static const UNIFORM_BLOCK_MAX_SIZE = 256;
-
 /// Visitor that sets a uniform
 /// Visitor that sets a uniform
 struct SetupMaterialVariableVisitor
 struct SetupMaterialVariableVisitor
 {
 {
@@ -76,40 +18,28 @@ struct SetupMaterialVariableVisitor
 	const Frustumable* fr = nullptr;
 	const Frustumable* fr = nullptr;
 	Renderer* r = nullptr;
 	Renderer* r = nullptr;
 	Renderable* renderable = nullptr;
 	Renderable* renderable = nullptr;
-	Array<U8, UNIFORM_BLOCK_MAX_SIZE> clientBlock;
+	Array<U8, RenderableDrawer::UNIFORM_BLOCK_MAX_SIZE> clientBlock;
+	RenderableMaterialVariable* rvar = nullptr;
 
 
 	/// Set a uniform in a client block
 	/// Set a uniform in a client block
 	template<typename T>
 	template<typename T>
-	static void uniSet(const ShaderProgramUniformVariable& uni, const T& value)
+	void uniSet(const ShaderProgramUniformVariable& uni, const T& value)
 	{
 	{
-		uni.setClientMemory(&clientBlock[0], UNIFORM_BLOCK_MAX_SIZE, &value, 1);
+		ANKI_ASSERT(0);
 	}
 	}
 
 
 	template<typename TProp>
 	template<typename TProp>
 	void visit(TProp& x)
 	void visit(TProp& x)
 	{
 	{
-		MaterialVariableProperty<typename TProp::Value>& mprop =
-			static_cast<MaterialVariableProperty<typename TProp::Value>&>(x);
-
-		const MaterialVariable& mv = mprop.getMaterialVariable();
+		const MaterialVariable& mv = rvar->getMaterialVariable();
 
 
 		const ShaderProgramUniformVariable* uni =
 		const ShaderProgramUniformVariable* uni =
 			mv.findShaderProgramUniformVariable(key);
 			mv.findShaderProgramUniformVariable(key);
-
 		if(!uni)
 		if(!uni)
 		{
 		{
 			return;
 			return;
 		}
 		}
 
 
-		// Sanity check
-		//
-		ANKI_ASSERT(mprop.getBuildinId() != BI_UNITIALIZED);
-		if(!mv.hasValue() && mprop.getBuildinId() == BT_NO_BUILDIN)
-		{
-			ANKI_LOGW("Material variable no building and not initialized: "
-				<< mv.getName());
-		}
-
 		// Set uniform
 		// Set uniform
 		//
 		//
 		const Transform* rwtrf = renderable->getRenderableWorldTransform();
 		const Transform* rwtrf = renderable->getRenderableWorldTransform();
@@ -121,15 +51,15 @@ struct SetupMaterialVariableVisitor
 		Mat4 mvMat;
 		Mat4 mvMat;
 		Bool mvMatCalculated = false; // Opt
 		Bool mvMatCalculated = false; // Opt
 
 
-		switch(mprop.getBuildinId())
+		switch(rvar->getBuildinId())
 		{
 		{
-		case BT_NO_BUILDIN:
-			uniSet(*uni, mprop.getValue());
+		case BMV_NO_BUILDIN:
+			uniSet(*uni, x);
 			break;
 			break;
-		case BI_MODEL_VIEW_PROJECTION_MATRIX:
+		case BMV_MODEL_VIEW_PROJECTION_MATRIX:
 			uniSet(*uni, mvpMat);
 			uniSet(*uni, mvpMat);
 			break;
 			break;
-		case BI_MODEL_VIEW_MATRIX:
+		case BMV_MODEL_VIEW_MATRIX:
 			if(!mvMatCalculated)
 			if(!mvMatCalculated)
 			{
 			{
 				mvMat = mMat * fr->getViewMatrix();
 				mvMat = mMat * fr->getViewMatrix();
@@ -137,7 +67,7 @@ struct SetupMaterialVariableVisitor
 			}
 			}
 			uniSet(*uni, mvMat);
 			uniSet(*uni, mvMat);
 			break;
 			break;
-		case BI_NORMAL_MATRIX:
+		case BMV_NORMAL_MATRIX:
 			if(!mvMatCalculated)
 			if(!mvMatCalculated)
 			{
 			{
 				mvMat = mMat * fr->getViewMatrix();
 				mvMat = mMat * fr->getViewMatrix();
@@ -145,51 +75,58 @@ struct SetupMaterialVariableVisitor
 			}
 			}
 			uniSet(*uni, mvMat.getRotationPart());
 			uniSet(*uni, mvMat.getRotationPart());
 			break;
 			break;
-		case BI_BLURRING:
+		case BMV_BLURRING:
 			uniSet(*uni, 0.0);
 			uniSet(*uni, 0.0);
 			break;
 			break;
+		default:
+			ANKI_ASSERT(0);
+			break;
 		}
 		}
 	}
 	}
 };
 };
 
 
+/// Specialize the material accepted types. The un-specialized will be used for
+/// all Property types like strings, we don't need strings in our case
+#define TEMPLATE_SPECIALIZATION(type) \
+	template<> \
+	void SetupMaterialVariableVisitor::uniSet<type>( \
+		const ShaderProgramUniformVariable& uni, const type& value) \
+	{ \
+		if(uni.getUniformBlock()) \
+		{ \
+			uni.setClientMemory(&clientBlock[0], \
+				RenderableDrawer::UNIFORM_BLOCK_MAX_SIZE, \
+				&value, 1); \
+		} \
+		else \
+		{ \
+			uni.set(value); \
+		} \
+	}
+
+TEMPLATE_SPECIALIZATION(F32)
+TEMPLATE_SPECIALIZATION(Vec2)
+TEMPLATE_SPECIALIZATION(Vec3)
+TEMPLATE_SPECIALIZATION(Vec4)
+TEMPLATE_SPECIALIZATION(Mat3)
+TEMPLATE_SPECIALIZATION(Mat4)
+
 // Texture specialization
 // Texture specialization
 template<>
 template<>
-void uniSet<TextureResourcePointer>(
-	const ShaderProgramUniformVariable& uni,
-	const TextureResourcePointer& x,
-	void*)
+void SetupMaterialVariableVisitor::uniSet<TextureResourcePointer>(
+	const ShaderProgramUniformVariable& uni, 
+	const TextureResourcePointer& value)
 {
 {
-	const Texture* tex = x.get();
+	const Texture* tex = value.get();
 	uni.set(*tex);
 	uni.set(*tex);
 }
 }
 
 
-//==============================================================================
-void RenderableDrawer::setBuildinIds(Renderable& renderable)
-{
-	SetBuildinIdVisitor vis;
-
-	for(auto it = renderable.getPropertiesBegin();
-		it != renderable.getPropertiesEnd(); ++it)
-	{
-		PropertyBase* prop = *it;
-
-		pbase->acceptVisitor(vis);
-
-		if(!vis.setted)
-		{
-			return;
-		}
-	}
-}
-
 //==============================================================================
 //==============================================================================
 void RenderableDrawer::setupShaderProg(
 void RenderableDrawer::setupShaderProg(
 	const PassLevelKey& key,
 	const PassLevelKey& key,
 	const Frustumable& fr,
 	const Frustumable& fr,
 	Renderable& renderable)
 	Renderable& renderable)
 {
 {
-	setBuildinIds(renderable);
-
 	const Material& mtl = renderable.getMaterial();
 	const Material& mtl = renderable.getMaterial();
 	const ShaderProgram& sprog = mtl.findShaderProgram(key);
 	const ShaderProgram& sprog = mtl.findShaderProgram(key);
 
 
@@ -202,19 +139,21 @@ void RenderableDrawer::setupShaderProg(
 	vis.renderable = &renderable;
 	vis.renderable = &renderable;
 	vis.r = r;
 	vis.r = r;
 
 
-	for(auto it = renderable.getPropertiesBegin();
-		it != renderable.getPropertiesEnd(); ++it)
+	for(auto it = renderable.getVariablesBegin();
+		it != renderable.getVariablesEnd(); ++it)
 	{
 	{
-		PropertyBase* pbase = *it;
-		pbase->acceptVisitor(vis);
+		RenderableMaterialVariable* rvar = *it;
+		vis.rvar = rvar;
+		rvar->getMaterialVariable().acceptVisitor(vis);
 	}
 	}
 
 
-	const ShaderProgramUniformBlock* block = mtl->getUniformBlock();
+	const ShaderProgramUniformBlock* block = mtl.getCommonUniformBlock();
 	if(block)
 	if(block)
 	{
 	{
 		ANKI_ASSERT(block->getSize() <= UNIFORM_BLOCK_MAX_SIZE);
 		ANKI_ASSERT(block->getSize() <= UNIFORM_BLOCK_MAX_SIZE);
+		ANKI_ASSERT(block->getBinding() == 0);
 		renderable.getUbo().write(&vis.clientBlock[0]);
 		renderable.getUbo().write(&vis.clientBlock[0]);
-		renderable.getUbo().setBindingPoint(0);
+		renderable.getUbo().setBinding(0);
 	}
 	}
 }
 }
 
 
@@ -238,7 +177,6 @@ void RenderableDrawer::render(const Frustumable& fr, uint pass,
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	vao.bind();
 	vao.bind();
 	glDrawElements(GL_TRIANGLES, indecesNum, GL_UNSIGNED_SHORT, 0);
 	glDrawElements(GL_TRIANGLES, indecesNum, GL_UNSIGNED_SHORT, 0);
-	vao.unbind();
 }
 }
 
 
 }  // end namespace anki
 }  // end namespace anki

+ 10 - 10
src/renderer/Is.cpp

@@ -366,35 +366,35 @@ void Is::initInternal(const RendererInitializer& initializer)
 
 
 	ublock = &lightPassProg->findUniformBlock("commonBlock");
 	ublock = &lightPassProg->findUniformBlock("commonBlock");
 	if(ublock->getSize() != sizeof(ShaderCommonUniforms)
 	if(ublock->getSize() != sizeof(ShaderCommonUniforms)
-		|| ublock->getBindingPoint() != COMMON_UNIFORMS_BLOCK_BINDING)
+		|| ublock->getBinding() != COMMON_UNIFORMS_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the commonBlock");
 		throw ANKI_EXCEPTION("Problem with the commonBlock");
 	}
 	}
 
 
 	ublock = &lightPassProg->findUniformBlock("pointLightsBlock");
 	ublock = &lightPassProg->findUniformBlock("pointLightsBlock");
 	if(ublock->getSize() != sizeof(ShaderPointLights)
 	if(ublock->getSize() != sizeof(ShaderPointLights)
-		|| ublock->getBindingPoint() != POINT_LIGHTS_BLOCK_BINDING)
+		|| ublock->getBinding() != POINT_LIGHTS_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
 		throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
 	}
 	}
 
 
 	ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
 	ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
 	if(ublock->getSize() != sizeof(ShaderSpotLights)
 	if(ublock->getSize() != sizeof(ShaderSpotLights)
-		|| ublock->getBindingPoint() != SPOT_LIGHTS_BLOCK_BINDING)
+		|| ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
 		throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
 	}
 	}
 
 
 	ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
 	ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
 	if(ublock->getSize() != sizeof(ShaderSpotLights)
 	if(ublock->getSize() != sizeof(ShaderSpotLights)
-		|| ublock->getBindingPoint() != SPOT_LIGHTS_BLOCK_BINDING)
+		|| ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
 		throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
 	}
 	}
 
 
 	ublock = &lightPassProg->findUniformBlock("tilesBlock");
 	ublock = &lightPassProg->findUniformBlock("tilesBlock");
 	if(ublock->getSize() != sizeof(ShaderTiles)
 	if(ublock->getSize() != sizeof(ShaderTiles)
-		|| ublock->getBindingPoint() != TILES_BLOCK_BINDING)
+		|| ublock->getBinding() != TILES_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the tilesBlock");
 		throw ANKI_EXCEPTION("Problem with the tilesBlock");
 	}
 	}
@@ -764,6 +764,11 @@ void Is::lightPass()
 	// shader prog
 	// shader prog
 	lightPassProg->bind();
 	lightPassProg->bind();
 
 
+	commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
+	pointLightsUbo.setBinding(POINT_LIGHTS_BLOCK_BINDING);
+	spotLightsUbo.setBinding(SPOT_LIGHTS_BLOCK_BINDING);
+	tilesUbo.setBinding(TILES_BLOCK_BINDING);
+
 	lightPassProg->findUniformVariable("msFai0").set(r->getMs().getFai0());
 	lightPassProg->findUniformVariable("msFai0").set(r->getMs().getFai0());
 	lightPassProg->findUniformVariable("msDepthFai").set(
 	lightPassProg->findUniformVariable("msDepthFai").set(
 		r->getMs().getDepthFai());
 		r->getMs().getDepthFai());
@@ -796,11 +801,6 @@ void Is::run()
 		commonUboUpdateTimestamp = Timestamp::getTimestamp();
 		commonUboUpdateTimestamp = Timestamp::getTimestamp();
 	}
 	}
 
 
-	commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
-	pointLightsUbo.setBinding(POINT_LIGHTS_BLOCK_BINDING);
-	spotLightsUbo.setBinding(SPOT_LIGHTS_BLOCK_BINDING);
-	tilesUbo.setBinding(TILES_BLOCK_BINDING);
-
 	// Update tiles
 	// Update tiles
 	updateTiles();
 	updateTiles();
 
 

+ 3 - 3
src/renderer/MainRenderer.cpp

@@ -96,7 +96,7 @@ void MainRenderer::render(Scene& scene)
 	GlStateSingleton::get().disable(GL_BLEND);
 	GlStateSingleton::get().disable(GL_BLEND);
 	sProg->bind();
 	sProg->bind();
 #if 0
 #if 0
-	const Texture& finalFai = pps.getHdr().getFai();
+	const Texture& finalFai = ms.getFai0();
 #else
 #else
 	const Texture& finalFai = pps.getFai();
 	const Texture& finalFai = pps.getFai();
 #endif
 #endif
@@ -112,8 +112,8 @@ void MainRenderer::takeScreenshotTga(const char* filename)
 	fs.open(filename, std::ios::out | std::ios::binary);
 	fs.open(filename, std::ios::out | std::ios::binary);
 	if(!fs.is_open())
 	if(!fs.is_open())
 	{
 	{
-		throw ANKI_EXCEPTION("Cannot create screenshot. File \""
-			+ filename + "\"");
+		throw ANKI_EXCEPTION("Cannot write screenshot file:"
+			+ filename);
 	}
 	}
 
 
 	// write headers
 	// write headers

+ 1 - 0
src/renderer/Ms.cpp

@@ -73,6 +73,7 @@ void Ms::run()
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 
 	// render all
 	// render all
+	r->getSceneDrawer().prepareDraw();
 	VisibilityInfo& vi =
 	VisibilityInfo& vi =
 		r->getScene().getActiveCamera().getFrustumable()->getVisibilityInfo();
 		r->getScene().getActiveCamera().getFrustumable()->getVisibilityInfo();
 	for(auto it = vi.getRenderablesBegin(); it != vi.getRenderablesEnd(); ++it)
 	for(auto it = vi.getRenderablesBegin(); it != vi.getRenderablesEnd(); ++it)

+ 5 - 3
src/renderer/Renderer.cpp

@@ -31,7 +31,9 @@ void Renderer::init(const RendererInitializer& initializer)
 	}
 	}
 
 
 	// init the stages. Careful with the order!!!!!!!!!!
 	// init the stages. Careful with the order!!!!!!!!!!
-	ms.init(initializer);
+	tiler.init(this);
+
+	ms.init(initializer);;
 	is.init(initializer);
 	is.init(initializer);
 	pps.init(initializer);
 	pps.init(initializer);
 	bs.init(initializer);
 	bs.init(initializer);
@@ -80,10 +82,10 @@ void Renderer::render(Scene& scene_)
 	viewProjectionMat = cam.getViewProjectionMatrix();
 	viewProjectionMat = cam.getViewProjectionMatrix();
 
 
 	ms.run();
 	ms.run();
+	//tiler.updateTiles(scene->getActiveCamera(), ms.getDepthFai());
 	is.run();
 	is.run();
 	pps.run();
 	pps.run();
-	/*bs.run();
-	pps.runPostPass();*/
+	//bs.run();
 
 
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 	++framesNum;
 	++framesNum;

+ 2 - 0
src/renderer/Sm.cpp

@@ -79,6 +79,8 @@ void Sm::prepareDraw()
 	// for artifacts
 	// for artifacts
 	glPolygonOffset(2.0, 2.0); // keep the values as low as possible!!!!
 	glPolygonOffset(2.0, 2.0); // keep the values as low as possible!!!!
 	GlStateSingleton::get().enable(GL_POLYGON_OFFSET_FILL);
 	GlStateSingleton::get().enable(GL_POLYGON_OFFSET_FILL);
+
+	r->getSceneDrawer().prepareDraw();
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 327 - 0
src/renderer/Tiler.cpp

@@ -0,0 +1,327 @@
+#include "anki/renderer/Tiler.h"
+#include "anki/renderer/Renderer.h"
+#include "anki/resource/ShaderProgramResource.h"
+#include "anki/core/ThreadPool.h"
+#include "anki/scene/Camera.h"
+
+namespace anki {
+
+//==============================================================================
+/// Job that updates the left, right, top and buttom tile planes
+struct UpdateTiles4PlanesPerspectiveCameraJob: ThreadJob
+{
+	Tiler* tiler;
+	PerspectiveCamera* cam;
+
+	void operator()(U threadId, U threadsCount)
+	{
+		U64 start, end;
+		choseStartEnd(threadId, threadsCount, 
+			Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT, start, end);
+
+		const F32 fx = cam->getFovX();
+		const F32 fy = cam->getFovY();
+		const F32 n = cam->getNear();
+
+		F32 l = 2.0 * n * tan(fx / 2.0);
+		F32 l6 = l / Tiler::TILES_X_COUNT;
+		F32 o = 2.0 * n * tan(fy / 2.0);
+		F32 o6 = o / Tiler::TILES_Y_COUNT;
+
+		for(U64 k = start; k < end; k++)
+		{
+			U i = k % Tiler::TILES_X_COUNT;
+			U j = k / Tiler::TILES_X_COUNT;
+
+			Array<Plane, Frustum::FP_COUNT>& planes = tiler->tiles[j][i].planes;
+			updatePlanes(l, l6, o, o6, i, j, planes);
+		}
+	}
+
+	void updatePlanes(
+		const F32 l, const F32 l6, const F32 o, const F32 o6,
+		const U i, const U j,
+		Array<Plane, Frustum::FP_COUNT>& planes)
+	{
+		Vec3 a, b;
+		const F32 n = cam->getNear();
+
+		// left
+		a = Vec3((I(i) - I(Tiler::TILES_X_COUNT) / 2) * l6, 0.0, -n);
+		b = a.cross(Vec3(0.0, 1.0, 0.0));
+		b.normalize();
+
+		planes[Frustum::FP_LEFT] = Plane(b, 0.0);
+
+		// right
+		a = Vec3((I(i) - I(Tiler::TILES_X_COUNT) / 2 + 1) * l6, 0.0, -n);
+		b = Vec3(0.0, 1.0, 0.0).cross(a);
+		b.normalize();
+
+		planes[Frustum::FP_RIGHT] = Plane(b, 0.0);
+
+		// bottom
+		a = Vec3(0.0, (I(j) - I(Tiler::TILES_Y_COUNT) / 2) * o6, -n);
+		b = Vec3(1.0, 0.0, 0.0).cross(a);
+		b.normalize();
+
+		planes[Frustum::FP_BOTTOM] = Plane(b, 0.0);
+
+		// bottom
+		a = Vec3(0.0, (I(j) - I(Tiler::TILES_Y_COUNT) / 2 + 1) * o6, -n);
+		b = a.cross(Vec3(1.0, 0.0, 0.0));
+		b.normalize();
+
+		planes[Frustum::FP_TOP] = Plane(b, 0.0);
+	}
+};
+
+//==============================================================================
+/// Job that updates the near and far tile planes and transforms them
+struct UpdateTiles2PlanesJob: ThreadJob
+{
+	F32 (*pixels)[Is::TILES_Y_COUNT][Is::TILES_X_COUNT][2];
+	Tiler* tiler;
+	Camera* cam;
+
+	void operator()(U threadId, U threadsCount)
+	{
+		U64 start, end;
+		choseStartEnd(threadId, threadsCount, 
+			Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT, start, end);
+
+		// Calc planes for this camera
+		Vec2 planes;
+		Renderer::calcPlanes(Vec2(cam->getNear(), cam->getFar()), planes);
+
+		for(U64 k = start; k < end; k++)
+		{
+			U i = k % Tiler::TILES_X_COUNT;
+			U j = k / Tiler::TILES_X_COUNT;
+			Tiler::Tile& tile = tiler->tiles[j][i];
+
+			// Calculate depth as you do it for the vertex position inside 
+			// the shaders
+			F32 minZ = planes.y() / (planes.x() + (*pixels)[j][i][0]);
+			F32 maxZ = -planes.y() / (planes.x() + (*pixels)[j][i][1]);
+
+			tile.planes[Frustum::FP_NEAR] = Plane(Vec3(0.0, 0.0, -1.0), minZ);
+			tile.planes[Frustum::FP_FAR] = Plane(Vec3(0.0, 0.0, 1.0), maxZ);
+
+			// Transform all planes
+			Transform trf = Transform(cam->getWorldTransform());
+			for(U k = 0; k < Frustum::FP_COUNT; k++)
+			{
+				tile.planesWSpace[k] = tile.planes[k].getTransformed(trf);
+			}
+		}
+	}
+};
+
+//==============================================================================
+Tiler::Tiler()
+{}
+
+//==============================================================================
+Tiler::~Tiler()
+{}
+
+//==============================================================================
+void Tiler::init(Renderer* r_)
+{
+	try
+	{
+		initInternal(r_);
+	}
+	catch(const std::exception& e)
+	{
+		throw ANKI_EXCEPTION("Failed to init tiler") << e;
+	}
+}
+
+//==============================================================================
+void Tiler::initInternal(Renderer* r_)
+{
+	r = r_;
+
+	// Load the program
+	std::string pps =
+		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
+		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n"
+		"#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
+		"#define RENDERER_HEIGHT " + std::to_string(r->getHeight()) + "\n";
+
+	prog.load(ShaderProgramResource::createSrcCodeToCache(
+		"shaders/IsMinMax.glsl", pps.c_str()).c_str());
+
+	// Create FBO
+	Renderer::createFai(TILES_X_COUNT, TILES_Y_COUNT, GL_RG32UI,
+		GL_RG_INTEGER, GL_UNSIGNED_INT, fai);
+	fai.setFiltering(Texture::TFT_NEAREST);
+
+	fbo.create();
+	fbo.setColorAttachments({&fai});
+	if(!fbo.isComplete())
+	{
+		throw ANKI_EXCEPTION("FBO not complete");
+	}
+}
+
+//==============================================================================
+void Tiler::updateTiles(Camera& cam, const Texture& depthMap)
+{
+	//
+	// In the meantime update the 4 planes for all the tiles
+	//
+	update4Planes(cam);
+
+	//
+	// Issue the min/max draw call
+	//
+	fbo.bind();
+	prog->bind();
+	GlStateSingleton::get().setViewport(0, 0, TILES_X_COUNT, TILES_Y_COUNT);
+	prog->findUniformVariable("depthMap").set(depthMap);
+
+	r->drawQuad();
+
+#if ANKI_GL == ANKI_GL_ES
+	// For Mali T6xx do a flush because the GPU will stay doing nothing until 
+	// read pixels later on where it will be forced to flush
+	glFlush();
+#endif
+
+	//
+	// Read pixels from the min/max pass
+	//
+
+	F32 pixels[TILES_Y_COUNT][TILES_X_COUNT][2];
+#if ANKI_GL == ANKI_GL_DESKTOP
+	// It seems read from texture is a bit faster than readpixels on nVidia
+	fai.readPixels(pixels);
+#else
+	glReadPixels(0, 0, TILES_X_COUNT, TILES_Y_COUNT, GL_RG_INTEGER,
+		GL_UNSIGNED_INT, &pixels[0][0][0]);
+#endif
+
+	// 
+	// Update the 2 planes and transform the planes
+	// 
+	update2Planes(cam, &pixels);
+
+	prevCam = &cam;
+}
+
+//==============================================================================
+void Tiler::update4Planes(Camera& cam)
+{
+	U32 camTimestamp = cam.getFrustumable()->getFrustumableTimestamp();
+	if(camTimestamp < planes4UpdateTimestamp && prevCam == &cam)
+	{
+		// Early exit because:
+		// - it is the same camera as before and
+		// - the camera frustum have not changed
+		return;
+	}
+#if 0
+	ANKI_LOGI("Updating 4 planes");
+#endif
+
+	// Update the planes in parallel
+	// 
+	ThreadPool& threadPool = ThreadPoolSingleton::get();
+
+	// Dont even think of defining that in the switch
+	Array<UpdateTiles4PlanesPerspectiveCameraJob, ThreadPool::MAX_THREADS> jobs;
+
+	switch(cam.getCameraType())
+	{
+	case Camera::CT_PERSPECTIVE:
+		for(U i = 0; i < threadPool.getThreadsCount(); i++)
+		{	
+			jobs[i].tiler = this;
+			jobs[i].cam = static_cast<PerspectiveCamera*>(&cam);
+			threadPool.assignNewJob(i, &jobs[i]);
+		}
+		break;
+	default:
+		ANKI_ASSERT(0 && "Unimplemented");
+		break;
+	}
+
+	threadPool.waitForAllJobsToFinish();
+
+	planes4UpdateTimestamp = Timestamp::getTimestamp();
+}
+
+//==============================================================================
+void Tiler::update2Planes(Camera& cam, 
+	F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2])
+{
+	ThreadPool& threadPool = ThreadPoolSingleton::get();
+	UpdateTiles2PlanesJob jobs[ThreadPool::MAX_THREADS];
+	
+	for(U i = 0; i < threadPool.getThreadsCount(); i++)
+	{
+		jobs[i].pixels = pixels;
+		jobs[i].tiler = this;
+		jobs[i].cam = &cam;
+
+		threadPool.assignNewJob(i, &jobs[i]);
+	}
+
+	threadPool.waitForAllJobsToFinish();
+}
+
+//==============================================================================
+Bool Tiler::test(const CollisionShape& cs,
+	Array<U32, TILES_X_COUNT * TILES_Y_COUNT>* tileIds) const
+{
+	if(tileIds)
+	{
+		U32* ip = &(*tileIds)[0];
+		for(U i = 0; i < tiles1d.getSize(); i++)
+		{
+			Bool inside = true;
+			for(const Plane& plane : tiles1d[i].planesWSpace)
+			{
+				if(cs.testPlane(plane) < 0.0)
+				{
+					inside = false;
+					break;
+				}
+			}
+
+			if(inside)
+			{
+				*ip++ = i;
+			}
+		}
+
+		return ip != &(*tileIds)[0];
+	}
+	else
+	{
+		for(const Tile& tile : tiles1d)
+		{
+			Bool inside = true;
+			for(const Plane& plane : tile.planesWSpace)
+			{
+				if(cs.testPlane(plane) < 0.0)
+				{
+					inside = false;
+					break;
+				}
+			}
+
+			if(inside)
+			{
+				return true;
+			}
+		}
+
+		return false;
+	}
+}
+
+} // end namespace anki

+ 12 - 3
src/resource/Material.cpp

@@ -10,6 +10,8 @@
 #include <map>
 #include <map>
 #include <fstream>
 #include <fstream>
 
 
+#define ENABLE_UBOS 0
+
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
@@ -317,10 +319,17 @@ void Material::populateVariables(const MaterialShaderProgramCreator& mspc)
 		for(const ShaderProgramUniformVariable& v :
 		for(const ShaderProgramUniformVariable& v :
 			(*sProg)->getUniformVariables())
 			(*sProg)->getUniformVariables())
 		{
 		{
+#if ENABLE_UBOS
 			const ShaderProgramUniformBlock* bl = v.getUniformBlock();
 			const ShaderProgramUniformBlock* bl = v.getUniformBlock();
-			(void)bl; // Make compiler happy
-			ANKI_ASSERT(bl == nullptr || v.getGlDataType() == GL_SAMPLER_2D);
-			ANKI_ASSERT(bl == nullptr || bl->getName() == blockName);
+			if(bl == nullptr)
+			{
+				ANKI_ASSERT(v.getGlDataType() == GL_SAMPLER_2D);
+			}
+			else
+			{
+				ANKI_ASSERT(bl->getName() == blockName);
+			}
+#endif
 
 
 			allVarNames[v.getName()] = v.getGlDataType();
 			allVarNames[v.getName()] = v.getGlDataType();
 		}
 		}

+ 12 - 3
src/resource/MaterialShaderProgramCreator.cpp

@@ -6,6 +6,8 @@
 #include <algorithm>
 #include <algorithm>
 #include <sstream>
 #include <sstream>
 
 
+#define ENABLE_UBOS 0
+
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
@@ -33,8 +35,9 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 	} while(shaderEl);
 	} while(shaderEl);
 
 
 	// Create block
 	// Create block
+#if ENABLE_UBOS
 	StringList block;
 	StringList block;
-	block.push_back("layout(std140, row_major, binding = 0) "
+	block.push_back("layout(shared, row_major, binding = 0) "
 		"uniform commonBlock\n{");
 		"uniform commonBlock\n{");
 	for(Input* in : inputs)
 	for(Input* in : inputs)
 	{
 	{
@@ -44,7 +47,7 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 			continue;
 			continue;
 		}
 		}
 
 
-		block.push_back("\tuniform " + in->type + " " + in->name + "_;");
+		block.push_back("\tuniform " + in->type + " " + in->name + ";");
 	}
 	}
 	block.push_back("};\n");
 	block.push_back("};\n");
 
 
@@ -53,6 +56,7 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 		source = block.join("\n") + srcLines.join("\n");
 		source = block.join("\n") + srcLines.join("\n");
 	}
 	}
 	else
 	else
+#endif
 	{
 	{
 		source = srcLines.join("\n");
 		source = srcLines.join("\n");
 	}
 	}
@@ -153,7 +157,12 @@ void MaterialShaderProgramCreator::parseInputTag(
 
 
 	if(inpvar->const_ == false)
 	if(inpvar->const_ == false)
 	{
 	{
-		//line = "uniform " + inpvar->type + " " + inpvar->name + ";";
+#if ENABLE_UBOS
+		if(inpvar->type == "sampler2D")
+#endif
+		{
+			line = "uniform " + inpvar->type + " " + inpvar->name + ";";
+		}
 	}
 	}
 	else
 	else
 	{
 	{

+ 50 - 10
src/scene/Renderable.cpp

@@ -1,6 +1,8 @@
 #include "anki/scene/Renderable.h"
 #include "anki/scene/Renderable.h"
 #include "anki/resource/Material.h"
 #include "anki/resource/Material.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/TextureResource.h"
+#include "anki/gl/ShaderProgram.h"
+#include "anki/core/Logger.h"
 
 
 namespace anki {
 namespace anki {
 
 
@@ -8,26 +10,63 @@ namespace anki {
 // CreateNewPropertyVisitor                                                    =
 // CreateNewPropertyVisitor                                                    =
 //==============================================================================
 //==============================================================================
 
 
-/// Create a new property given a material variable
+/// Create a new RenderableMaterialVariable given a MaterialVariable
 struct CreateNewPropertyVisitor
 struct CreateNewPropertyVisitor
 {
 {
 	const MaterialVariable* mvar = nullptr;
 	const MaterialVariable* mvar = nullptr;
 	PropertyMap* pmap = nullptr;
 	PropertyMap* pmap = nullptr;
-	Renderable::MaterialVariableProperties* rprops = nullptr;
+	Renderable::RenderableMaterialVariables* vars = nullptr;
 
 
 	template<typename T>
 	template<typename T>
 	void visit(const T&) const
 	void visit(const T&) const
 	{
 	{
-		MaterialVariableProperty<T>* prop = new MaterialVariableProperty<T>(
-			mvar->getName().c_str(),
-			&(mvar->getValue<T>()),
+		RenderableMaterialVariable* rvar = new RenderableMaterialVariable(
 			mvar);
 			mvar);
 
 
-		pmap->addNewProperty(prop);
-		rprops->push_back(prop);
+		//pmap->addNewProperty(prop);
+		vars->push_back(rvar);
 	}
 	}
 };
 };
 
 
+//==============================================================================
+// RenderableMaterialVariable                                                  =
+//==============================================================================
+
+//==============================================================================
+
+static Array<const char*, BMV_COUNT - 1> buildinNames = {{
+	"modelViewProjectionMat",
+	"modelViewMat",
+	"normalMat",
+	"blurring"
+}};
+
+//==============================================================================
+RenderableMaterialVariable::RenderableMaterialVariable(
+	const MaterialVariable* mvar_)
+	: mvar(mvar_)
+{
+	// Set buildin id
+	const std::string& name = getName();
+
+	buildinId = BMV_NO_BUILDIN;
+	for(U i = 0; i < buildinNames.getSize(); i++)
+	{
+		if(name == buildinNames[i])
+		{
+			buildinId = (BuildinMaterialVariableId)(i + 1);
+			break;
+		}
+	}
+
+	// Sanity checks
+	if(!mvar->hasValue() && buildinId == BMV_NO_BUILDIN)
+	{
+		ANKI_LOGW("Material variable no buildin and not initialized: "
+			<< name);
+	}
+}
+
 //==============================================================================
 //==============================================================================
 // Renderable                                                                  =
 // Renderable                                                                  =
 //==============================================================================
 //==============================================================================
@@ -43,7 +82,7 @@ void Renderable::init(PropertyMap& pmap)
 
 
 	CreateNewPropertyVisitor vis;
 	CreateNewPropertyVisitor vis;
 	vis.pmap = &pmap;
 	vis.pmap = &pmap;
-	vis.rprops = &props;
+	vis.vars = &vars;
 
 
 	for(const MaterialVariable* mv : mtl.getVariables())
 	for(const MaterialVariable* mv : mtl.getVariables())
 	{
 	{
@@ -56,11 +95,12 @@ void Renderable::init(PropertyMap& pmap)
 	// binding
 	// binding
 
 
 	// Init the UBO
 	// Init the UBO
-	const ShaderProgramUniformBlock* block = mtl.getUniformBlock();
+	const ShaderProgramUniformBlock* block = mtl.getCommonUniformBlock();
 
 
 	if(block)
 	if(block)
 	{
 	{
-		ubo.create(block->getSize());
+		ubo.create(block->getSize(), nullptr);
+		//ubo.setBinding(20);
 	}
 	}
 }
 }
 
 

+ 1 - 1
testapp/Main.cpp

@@ -292,7 +292,7 @@ void mainLoop()
 
 
 		// Sleep
 		// Sleep
 		//
 		//
-#if 1
+#if 0
 		timer.stop();
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{
 		{