Browse Source

Making the Renderable class more instancing friendly

Panagiotis Christopoulos Charitos 13 years ago
parent
commit
f62a46495f

+ 2 - 2
include/anki/scene/ModelNode.h

@@ -80,8 +80,8 @@ public:
 		return modelPatch->getMaterial();
 	}
 
-	/// Overrides Renderable::getRenderableWorldTransform
-	const Transform* getRenderableWorldTransform() const
+	/// Overrides Renderable::getRenderableWorldTransforms
+	const Transform* getRenderableWorldTransforms() const
 	{
 		return &getWorldTransform();
 	}

+ 3 - 2
include/anki/scene/ParticleEmitter.h

@@ -111,12 +111,13 @@ public:
 	/// Implements  Renderable::getMaterial
 	const Material& getRenderableMaterial() const;
 
-	/// Overrides Renderable::getRenderableInstancingTransformations
-	virtual const Transform* getRenderableInstancingWorldTransforms() const
+	/// Overrides Renderable::getRenderableWorldTransforms
+	virtual const Transform* getRenderableWorldTransforms() const
 	{
 		return &instancingTransformations[0];
 	}
 
+	/// Overrides Renderable::getRenderableInstancesCount
 	virtual U32 getRenderableInstancesCount() const
 	{
 		return instancesCount;

+ 3 - 12
include/anki/scene/Renderable.h

@@ -21,7 +21,6 @@ enum BuildinMaterialVariableId
 	BMV_MODEL_VIEW_PROJECTION_MATRIX,
 	BMV_MODEL_VIEW_MATRIX,
 	BMV_NORMAL_MATRIX,
-	BMV_INSTANCING_MODEL_VIEW_PROJECTION_MATRICES,
 	BMV_BLURRING,
 	BMV_COUNT
 };
@@ -73,25 +72,17 @@ public:
 	/// Access the material
 	virtual const Material& getRenderableMaterial() const = 0;
 
-	/// Information for movables
-	virtual const Transform* getRenderableWorldTransform() const
-	{
-		return nullptr;
-	}
-
-	/// @name Instancing methods
-	/// @{
-
-	virtual const Transform* getRenderableInstancingWorldTransforms() const
+	/// Information for movables. It's actualy an array of transformations.
+	virtual const Transform* getRenderableWorldTransforms() const
 	{
 		return nullptr;
 	}
 
+	/// Used for instancing
 	virtual U32 getRenderableInstancesCount() const
 	{
 		return 1;
 	}
-	/// @}
 
 	/// @name Accessors
 	/// @{

+ 2 - 2
include/anki/scene/SkinNode.h

@@ -192,8 +192,8 @@ public:
 		return skinModelPatch->getMaterial();
 	}
 
-	/// Overrides Renderable::getRenderableWorldTransform
-	const Transform* getRenderableWorldTransform() const
+	/// Overrides Renderable::getRenderableWorldTransforms
+	const Transform* getRenderableWorldTransforms() const
 	{
 		return &getWorldTransform();
 	}

+ 178 - 144
include/anki/util/Visitor.h

@@ -10,6 +10,7 @@
 
 #include "anki/util/Assert.h"
 #include "anki/util/Array.h"
+#include "anki/util/StdTypes.h"
 
 namespace anki {
 
@@ -44,12 +45,12 @@ struct GetVariadicTypeId
 	template<typename Type, typename... Types_>
 	struct Helper<Type, Type, Types_...>
 	{
-		static const int ID = sizeof...(Types_);
+		static const I ID = sizeof...(Types_);
 	};
 
 	/// Get the id
 	template<typename Type>
-	static constexpr int get()
+	static constexpr I get()
 	{
 		return sizeof...(Types) - Helper<Type, Types...>::ID - 1;
 	}
@@ -67,11 +68,11 @@ template<typename... Types>
 struct GetTypeUsingId
 {
 	// Forward declaration
-	template<int id, typename... Types_>
+	template<I id, typename... Types_>
 	struct Helper;
 
 	// Declaration
-	template<int id, typename TFirst, typename... Types_>
+	template<I id, typename TFirst, typename... Types_>
 	struct Helper<id, TFirst, Types_...>: Helper<id - 1, Types_...>
 	{};
 
@@ -82,121 +83,10 @@ struct GetTypeUsingId
 		typedef TFirst DataType;
 	};
 
-	template<int id>
+	template<I id>
 	using DataType = typename Helper<id, Types...>::DataType;
 };
 
-/// A simple struct that creates an array of pointers to functions that have
-/// the same arguments but different body
-template<typename TVisitor, typename... Types>
-class JumpTable
-{
-public:
-	using FuncPtr = void (*)(TVisitor&, void*);
-
-	JumpTable()
-	{
-		init<Types...>();
-	}
-
-	/// Accessor
-	FuncPtr operator[](int i) const
-	{
-		return jumps[i];
-	}
-
-private:
-	/// Pointers to JumpPoint::visit static methods
-	Array<FuncPtr, sizeof...(Types)> jumps;
-
-	template<typename T>
-	static void visit(TVisitor& v, void* address)
-	{
-		v.template visit(*reinterpret_cast<T*>(address));
-	}
-
-	template<typename TFirst>
-	void init()
-	{
-		jumps[0] = &visit<TFirst>;
-	}
-
-	template<typename TFirst, typename TSecond, typename... Types_>
-	void init()
-	{
-		constexpr int i = sizeof...(Types) - sizeof...(Types_) - 1;
-		jumps[i] = &visit<TSecond>;
-		init<TFirst, Types_...>();
-	}
-};
-
-/// Jump table for types with common base
-template<typename TVisitor, typename TBase, typename... Types>
-class JumpTableCommonBase
-{
-public:
-	using FuncPtr = void (*)(TVisitor&, TBase&);
-
-	JumpTableCommonBase()
-	{
-		init<Types...>();
-	}
-
-	/// Accessor
-	FuncPtr operator[](int i) const
-	{
-		return jumps[i];
-	}
-
-private:
-	/// Pointers to JumpPoint::visit static methods
-	Array<FuncPtr, sizeof...(Types)> jumps;
-
-	template<typename T>
-	static void visit(TVisitor& v, TBase& base)
-	{
-		v.template visit(static_cast<T&>(base));
-	}
-
-	template<typename TFirst>
-	void init()
-	{
-		jumps[0] = &visit<TFirst>;
-	}
-
-	template<typename TFirst, typename TSecond, typename... Types_>
-	void init()
-	{
-		constexpr int i = sizeof...(Types) - sizeof...(Types_) - 1;
-		jumps[i] = &visit<TSecond>;
-		init<TFirst, Types_...>();
-	}
-};
-
-/// A simple struct that contains a static field with jump points
-template<typename TDerived, typename... Types>
-struct VisitorWrapper
-{
-	static const JumpTable<TDerived, Types...> jumpTable;
-};
-
-// A static
-template<typename TDerived, typename... Types>
-const JumpTable<TDerived, Types...>
-	VisitorWrapper<TDerived, Types...>::jumpTable;
-
-/// Jumps container for types with common base
-template<typename TDerived, typename TBase, typename... Types>
-struct VisitorWrapperCommonBase
-{
-	static const JumpTableCommonBase<TDerived, TBase, Types...> jumpTable;
-};
-
-// A static
-template<typename TDerived, typename TBase, typename... Types>
-const JumpTableCommonBase<TDerived, TBase, Types...>
-	VisitorWrapperCommonBase<TDerived, TBase, Types...>::jumpTable;
-
 } // end namespace visitor_detail
 
 /// Visitable class
@@ -213,13 +103,13 @@ public:
 		setupVisitable(t);
 	}
 
-	int getVisitableTypeId() const
+	I getVisitableTypeId() const
 	{
 		return what;
 	}
 
 	template<typename T>
-	static constexpr int getVariadicTypeId()
+	static constexpr I getVariadicTypeId()
 	{
 		return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
 	}
@@ -229,8 +119,7 @@ public:
 	void acceptVisitor(TVisitor& v)
 	{
 		ANKI_ASSERT(what != -1 && address != nullptr);
-		visitor_detail::VisitorWrapper<TVisitor, Types...>::
-			jumpTable[what](v, address);
+		acceptVisitorInternal<TVisitor, Types...>(v);
 	}
 
 	/// Apply visitor (const version)
@@ -238,8 +127,7 @@ public:
 	void acceptVisitor(TVisitor& v) const
 	{
 		ANKI_ASSERT(what != -1 && address != nullptr);
-		visitor_detail::VisitorWrapper<TVisitor, Types...>::
-			jumpTable[what](v, address);
+		acceptVisitorInternalConst<TVisitor, Types...>(v);
 	}
 
 	/// Setup the data
@@ -254,8 +142,73 @@ public:
 	}
 
 private:
-	int what = -1; ///< The type ID
+	I what = -1; ///< The type ID
 	void* address = nullptr; ///< The address to the data
+
+	/// @name Accept visitor template methods
+	/// @{
+	template<typename TVisitor, typename TFirst>
+	void acceptVisitorInternal(TVisitor& v)
+	{
+		switch(what)
+		{
+		case 0:
+			v.template visit(*reinterpret_cast<TFirst*>(address));
+			break;
+		default:
+			ANKI_ASSERT(0 && "Wrong type ID");
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst, typename TSecond, 
+		typename... Types_>
+	void acceptVisitorInternal(TVisitor& v)
+	{
+		constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
+
+		switch(what)
+		{
+		case i:
+			v.template visit(*reinterpret_cast<TSecond*>(address));
+			break;
+		default:
+			acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst>
+	void acceptVisitorInternalConst(TVisitor& v) const
+	{
+		switch(what)
+		{
+		case 0:
+			v.template visit(*reinterpret_cast<const TFirst*>(address));
+			break;
+		default:
+			ANKI_ASSERT(0 && "Wrong type ID");
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst, typename TSecond, 
+		typename... Types_>
+	void acceptVisitorInternalConst(TVisitor& v) const
+	{
+		constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
+
+		switch(what)
+		{
+		case i:
+			v.template visit(*reinterpret_cast<const TSecond*>(address));
+			break;
+		default:
+			acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
+			break;
+		}
+	}
+	/// @}
 };
 
 /// Visitable for types with common base
@@ -275,13 +228,13 @@ public:
 	{}
 #endif
 
-	int getVisitableTypeId() const
+	I getVisitableTypeId() const
 	{
 		return what;
 	}
 
 	template<typename T>
-	static constexpr int getVariadicTypeId()
+	static constexpr I getVariadicTypeId()
 	{
 		return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
 	}
@@ -291,31 +244,15 @@ public:
 	void acceptVisitor(TVisitor& v)
 	{
 		ANKI_ASSERT(what != -1);
-#if ANKI_DEBUG
-		TBase* base = dynamic_cast<TBase*>(this);
-		ANKI_ASSERT(base != nullptr);
-#else
-		TBase* base = static_cast<TBase*>(this);
-#endif
-		visitor_detail::VisitorWrapperCommonBase<TVisitor, TBase, Types...>::
-			jumpTable[what](v, *base);
+		acceptVisitorInternal<TVisitor, Types...>(v);
 	}
 
 	/// Apply const visitor
 	template<typename TVisitor>
 	void acceptVisitor(TVisitor& v) const
 	{
-		typedef const TBase CTBase;
 		ANKI_ASSERT(what != -1);
-#if ANKI_DEBUG
-		CTBase* base = dynamic_cast<CTBase*>(this);
-		ANKI_ASSERT(base != nullptr);
-#else
-		CTBase* base = static_cast<CTBase*>(this);
-#endif
-		visitor_detail::VisitorWrapperCommonBase
-			<TVisitor,CTBase, const Types...>::
-			jumpTable[what](v, *base);
+		acceptVisitorInternalConst<TVisitor, Types...>(v);
 	}
 
 	/// Setup the type ID
@@ -327,7 +264,104 @@ public:
 	}
 
 private:
-	int what = -1; ///< The type ID
+	I what = -1; ///< The type ID
+
+	/// @name Accept visitor template methods
+	/// @{
+	template<typename TVisitor, typename TFirst>
+	void acceptVisitorInternal(TVisitor& v)
+	{
+		switch(what)
+		{
+		case 0:
+			{
+#if ANKI_DEBUG
+				TFirst* base = dynamic_cast<TFirst*>(this);
+				ANKI_ASSERT(base != nullptr);
+#else
+				TFirst* base = static_cast<TFirst*>(this);
+#endif
+				v.template visit(*base);
+			}
+			break;
+		default:
+			ANKI_ASSERT(0 && "Wrong type ID");
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst, typename TSecond, 
+		typename... Types_>
+	void acceptVisitorInternal(TVisitor& v)
+	{
+		constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
+
+		switch(what)
+		{
+		case i:
+			{
+#if ANKI_DEBUG
+				TSecond* base = dynamic_cast<TSecond*>(this);
+				ANKI_ASSERT(base != nullptr);
+#else
+				TSecond* base = static_cast<TSecond*>(this);
+#endif
+				v.template visit(*base);
+			}
+			break;
+		default:
+			acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst>
+	void acceptVisitorInternalConst(TVisitor& v) const
+	{
+		switch(what)
+		{
+		case 0:
+			{
+#if ANKI_DEBUG
+				const TFirst* base = dynamic_cast<const TFirst*>(this);
+				ANKI_ASSERT(base != nullptr);
+#else
+				const TFirst* base = static_cast<const TFirst*>(this);
+#endif
+				v.template visit(*base);
+			}
+			break;
+		default:
+			ANKI_ASSERT(0 && "Wrong type ID");
+			break;
+		}
+	}
+
+	template<typename TVisitor, typename TFirst, typename TSecond, 
+		typename... Types_>
+	void acceptVisitorInternalConst(TVisitor& v) const
+	{
+		constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
+
+		switch(what)
+		{
+		case i:
+			{
+#if ANKI_DEBUG
+				const TSecond* base = dynamic_cast<const TSecond*>(this);
+				ANKI_ASSERT(base != nullptr);
+#else
+				const TSecond* base = static_cast<const TSecond*>(this);
+#endif
+				v.template visit(*base);
+			}
+			break;
+		default:
+			acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
+			break;
+		}
+	}
+	/// @}
 };
 /// @}
 

+ 30 - 32
src/renderer/Drawer.cpp

@@ -32,24 +32,26 @@ struct SetupMaterialVariableVisitor
 	template<typename MtlVariableTemplate>
 	void visit(MtlVariableTemplate& x)
 	{
-		const MaterialVariable& mv = rvar->getMaterialVariable();
+		const MaterialVariable& mvar = rvar->getMaterialVariable();
 
 		const ShaderProgramUniformVariable* uni =
-			mv.findShaderProgramUniformVariable(key);
+			mvar.findShaderProgramUniformVariable(key);
 		if(!uni)
 		{
 			return;
 		}
 
+		U32 instancesCount = renderable->getRenderableInstancesCount();
+
 		// Set uniform
 		//
-		const Transform* rwtrf = renderable->getRenderableWorldTransform();
+		const Transform* trfs = renderable->getRenderableWorldTransforms();
+		const Mat4& vp = fr->getViewProjectionMatrix();
+		const Mat4& v = fr->getViewMatrix();
 
-		Mat4 mMat = (rwtrf) ? Mat4(*rwtrf) : Mat4::getIdentity();
-		const Mat4& vpMat = fr->getViewProjectionMatrix();
+		const U maxInstances = 32; // XXX Use a proper vector with allocator
 
-		Mat4 mvMat;
-		Bool mvMatCalculated = false; // Opt
+		Array<Mat4, maxInstances> mv;
 
 		switch(rvar->getBuildinId())
 		{
@@ -59,45 +61,41 @@ struct SetupMaterialVariableVisitor
 			break;
 		case BMV_MODEL_VIEW_PROJECTION_MATRIX:
 			{
-				Mat4 mvpMat = vpMat * mMat;
-				uniSet(*uni, &mvpMat, 1);
+				ANKI_ASSERT(trfs != nullptr);
+				Array<Mat4, maxInstances> mvp;
+
+				for(U i = 0; i < instancesCount; i++)
+				{
+					mvp[i] = vp * Mat4(trfs[i]);
+				}
+
+				uniSet(*uni, &mvp[0], instancesCount);
 			}
 			break;
 		case BMV_MODEL_VIEW_MATRIX:
-			if(!mvMatCalculated)
-			{
-				mvMat = fr->getViewMatrix() * mMat;
-				mvMatCalculated = true;
-			}
-			uniSet(*uni, &mvMat, 1);
-			break;
-		case BMV_NORMAL_MATRIX:
 			{
-				if(!mvMatCalculated)
+				ANKI_ASSERT(trfs != nullptr);
+				Array<Mat4, maxInstances> mv;
+
+				for(U i = 0; i < instancesCount; i++)
 				{
-					mvMat = fr->getViewMatrix() * mMat;
-					mvMatCalculated = true;
+					mv[i] = v * Mat4(trfs[i]);
 				}
-				Mat3 rot = mvMat.getRotationPart();
-				uniSet(*uni, &rot, 1);
+
+				uniSet(*uni, &mv[0], instancesCount);
 			}
 			break;
-		case BMV_INSTANCING_MODEL_VIEW_PROJECTION_MATRICES:
+		case BMV_NORMAL_MATRIX:
 			{
-				U32 instancesCount = renderable->getRenderableInstancesCount();
-
-				Array<Mat4, 64> mvps;
-				ANKI_ASSERT(mvps.getSize() >= instancesCount);
-				const Transform* trfs =
-					renderable->getRenderableInstancingWorldTransforms();
-				ANKI_ASSERT(trfs != nullptr);
+				Array<Mat3, maxInstances> normm;
 
 				for(U i = 0; i < instancesCount; i++)
 				{
-					mvps[i] = vpMat * Mat4(trfs[i]);
+					Mat4 mv = v * Mat4(trfs[i]);
+					normm[i] = mv.getRotationPart();
 				}
 
-				uni->set(&mvps[0], instancesCount);
+				uniSet(*uni, &normm[0], instancesCount);
 			}
 			break;
 		case BMV_BLURRING:

+ 1 - 0
src/resource/Material.cpp

@@ -423,6 +423,7 @@ void Material::populateVariables(const MaterialShaderProgramCreator& mspc)
 		if(inpvar->value.size() != 0)
 		{
 			const StringList& value = inpvar->value;
+			ANKI_ASSERT(inpvar->arraySize <= 1 && "Arrays not supported");
 
 			// Get the value
 			switch(dataType)

+ 0 - 1
src/scene/Renderable.cpp

@@ -38,7 +38,6 @@ static Array<const char*, BMV_COUNT - 1> buildinNames = {{
 	"modelViewProjectionMat",
 	"modelViewMat",
 	"normalMat",
-	"instancingModelViewProjectionMatrices",
 	"blurring"}};
 
 //==============================================================================