Просмотр исходного кода

When rendering reduce state switching when possible

BearishSun 10 лет назад
Родитель
Сommit
0f7c76eb01

+ 1 - 0
BansheeCore/Include/BsCorePrerequisites.h

@@ -161,6 +161,7 @@ namespace BansheeEngine
 	class ShaderCore;
 	class ShaderCore;
 	class ViewportCore;
 	class ViewportCore;
 	class PassCore;
 	class PassCore;
+	class PassParametersCore;
 	class TechniqueCore;
 	class TechniqueCore;
 	class MaterialCore;
 	class MaterialCore;
 	class GpuProgramCore;
 	class GpuProgramCore;

+ 9 - 4
BansheeCore/Include/BsMaterial.h

@@ -66,8 +66,8 @@ namespace BansheeEngine
 	template<> struct TGpuProgramType<false> { typedef GpuProgramPtr Type; };
 	template<> struct TGpuProgramType<false> { typedef GpuProgramPtr Type; };
 	template<> struct TGpuProgramType<true> { typedef SPtr<GpuProgramCore> Type; };
 	template<> struct TGpuProgramType<true> { typedef SPtr<GpuProgramCore> Type; };
 
 
-	typedef TPassParameters<false> PassParameters;
-	typedef TPassParameters<true> PassParametersCore;
+	class BS_CORE_EXPORT PassParameters : public TPassParameters<false> {};
+	class BS_CORE_EXPORT PassParametersCore : public TPassParameters<true> {};
 
 
 	/**
 	/**
 	 * @brief	Material that controls how objects are rendered. It is represented by a shader and 
 	 * @brief	Material that controls how objects are rendered. It is represented by a shader and 
@@ -159,6 +159,10 @@ namespace BansheeEngine
 		template<> struct TGpuParamBlockBufferType < false > { typedef GpuParamBlockBuffer Type; };
 		template<> struct TGpuParamBlockBufferType < false > { typedef GpuParamBlockBuffer Type; };
 		template<> struct TGpuParamBlockBufferType < true > { typedef GpuParamBlockBufferCore Type; };
 		template<> struct TGpuParamBlockBufferType < true > { typedef GpuParamBlockBufferCore Type; };
 
 
+		template<bool Core> struct TPassParamsType {};
+		template<> struct TPassParamsType < false > { typedef PassParameters Type; };
+		template<> struct TPassParamsType < true > { typedef PassParametersCore Type; };
+
 		typedef typename TGpuParamsPtrType<Core>::Type GpuParamsType;
 		typedef typename TGpuParamsPtrType<Core>::Type GpuParamsType;
 		typedef typename TGpuParamTextureType<Core>::Type TextureType;
 		typedef typename TGpuParamTextureType<Core>::Type TextureType;
 		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerStateType;
 		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerStateType;
@@ -168,6 +172,7 @@ namespace BansheeEngine
 		typedef typename TPassType<Core>::Type PassType;
 		typedef typename TPassType<Core>::Type PassType;
 		typedef typename TTechniqueType<Core>::Type TechniqueType;
 		typedef typename TTechniqueType<Core>::Type TechniqueType;
 		typedef typename TShaderType<Core>::Type ShaderType;
 		typedef typename TShaderType<Core>::Type ShaderType;
+		typedef typename TPassParamsType<Core>::Type PassParamsType;
 
 
 		virtual ~TMaterial() { }
 		virtual ~TMaterial() { }
 
 
@@ -520,7 +525,7 @@ namespace BansheeEngine
 		 * @brief	Returns a set of parameters for all GPU programs
 		 * @brief	Returns a set of parameters for all GPU programs
 		 * 			in the specified shader pass.
 		 * 			in the specified shader pass.
 		 */
 		 */
-		SPtr<TPassParameters<Core>> getPassParameters(UINT32 passIdx) const { return mParametersPerPass[passIdx]; }
+		SPtr<PassParamsType> getPassParameters(UINT32 passIdx) const { return mParametersPerPass[passIdx]; }
 
 
 		/**
 		/**
 		 * @brief	Assign a parameter block buffer with the specified name.
 		 * @brief	Assign a parameter block buffer with the specified name.
@@ -569,7 +574,7 @@ namespace BansheeEngine
 		 */
 		 */
 		void throwIfNotInitialized() const;
 		void throwIfNotInitialized() const;
 
 
-		Vector<SPtr<TPassParameters<Core>>> mParametersPerPass;
+		Vector<SPtr<PassParamsType>> mParametersPerPass;
 		ShaderType mShader;
 		ShaderType mShader;
 		TechniqueType mBestTechnique;
 		TechniqueType mBestTechnique;
 	};
 	};

+ 20 - 16
BansheeCore/Source/BsMaterial.cpp

@@ -488,9 +488,9 @@ namespace BansheeEngine
 
 
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -524,9 +524,9 @@ namespace BansheeEngine
 
 
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -560,9 +560,9 @@ namespace BansheeEngine
 
 
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -595,9 +595,9 @@ namespace BansheeEngine
 		SPtr<Vector<TGpuParamSampState<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamSampState<Core>>>();
 		SPtr<Vector<TGpuParamSampState<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamSampState<Core>>>();
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -626,9 +626,9 @@ namespace BansheeEngine
 
 
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -681,7 +681,7 @@ namespace BansheeEngine
 			for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
 			for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
 			{
 			{
 				PassType curPass = mBestTechnique->getPass(i);
 				PassType curPass = mBestTechnique->getPass(i);
-				SPtr<TPassParameters<Core>> params = SPtr<TPassParameters<Core>>(new TPassParameters<Core>());
+				SPtr<PassParamsType> params = SPtr<PassParamsType>(new PassParamsType());
 
 
 				GpuProgramType vertProgram = curPass->getVertexProgram();
 				GpuProgramType vertProgram = curPass->getVertexProgram();
 				if (vertProgram)
 				if (vertProgram)
@@ -713,9 +713,9 @@ namespace BansheeEngine
 			// Assign param block buffers
 			// Assign param block buffers
 			for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 			for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 			{
 			{
-				SPtr<TPassParameters<Core>> params = *iter;
+				SPtr<PassParamsType> params = *iter;
 
 
-				for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+				for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 				{
 				{
 					GpuParamsType& paramPtr = params->getParamByIdx(i);
 					GpuParamsType& paramPtr = params->getParamByIdx(i);
 					if (paramPtr)
 					if (paramPtr)
@@ -903,9 +903,9 @@ namespace BansheeEngine
 
 
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
 		{
 		{
-			SPtr<TPassParameters<Core>> params = *iter;
+			SPtr<PassParamsType> params = *iter;
 
 
-			for (UINT32 i = 0; i < TPassParameters<Core>::NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
 			{
 			{
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				GpuParamsType& paramPtr = params->getParamByIdx(i);
 				if (paramPtr)
 				if (paramPtr)
@@ -990,7 +990,11 @@ namespace BansheeEngine
 		mBestTechnique = bestTechnique;
 		mBestTechnique = bestTechnique;
 		mValidShareableParamBlocks = validShareableParamBlocks;
 		mValidShareableParamBlocks = validShareableParamBlocks;
 		mValidParams = validParams;
 		mValidParams = validParams;
-		mParametersPerPass = passParams;
+
+		UINT32 numPassParams = (UINT32)passParams.size();
+		mParametersPerPass.resize(numPassParams);
+		for (UINT32 i = 0; i < numPassParams; i++)
+			mParametersPerPass[i] = passParams[i];
 	}
 	}
 
 
 	void MaterialCore::setShader(const SPtr<ShaderCore>& shader)
 	void MaterialCore::setShader(const SPtr<ShaderCore>& shader)

+ 9 - 8
BansheeEngine/Include/BsRenderQueue.h

@@ -8,13 +8,13 @@ namespace BansheeEngine
 {
 {
 	/**
 	/**
 	 * @brief	Controls if and how a render queue groups renderable objects
 	 * @brief	Controls if and how a render queue groups renderable objects
-	 * 			by material.
+	 * 			by material in order to reduce number of state changes.
 	 */
 	 */
-	enum class MaterialGrouping
+	enum class StateReduction
 	{
 	{
 		None, /**< No grouping based on material will be done. */
 		None, /**< No grouping based on material will be done. */
-		PreferMaterial, /**< Elements will be grouped by material first, by per-element sort type second. */
-		PreferSortType /**< Elements will be grouped by per-element sort type first, material second. */
+		Material, /**< Elements will be grouped by material first, by distance second. */
+		Distance /**< Elements will be grouped by distance first, material second. */
 	};
 	};
 
 
 	/**
 	/**
@@ -51,7 +51,7 @@ namespace BansheeEngine
 		};
 		};
 
 
 	public:
 	public:
-		RenderQueue(MaterialGrouping grouping = MaterialGrouping::PreferSortType);
+		RenderQueue(StateReduction grouping = StateReduction::Distance);
 		virtual ~RenderQueue() { }
 		virtual ~RenderQueue() { }
 
 
 		/**
 		/**
@@ -79,9 +79,10 @@ namespace BansheeEngine
 		const Vector<RenderQueueElement>& getSortedElements() const;
 		const Vector<RenderQueueElement>& getSortedElements() const;
 
 
 		/**
 		/**
-		 * @brief	Controls if and how a render queue groups renderable objects by material.
+		 * @brief	Controls if and how a render queue groups renderable objects by 
+		 * 			material in order to reduce number of state changes.
 		 */
 		 */
-		void setMaterialGrouping(MaterialGrouping grouping) { mGrouping = grouping; }
+		void setStateReduction(StateReduction mode) { mStateReductionMode = mode; }
 
 
 	protected:
 	protected:
 		/**
 		/**
@@ -104,6 +105,6 @@ namespace BansheeEngine
 		Vector<RenderableElement*> mElements;
 		Vector<RenderableElement*> mElements;
 
 
 		Vector<RenderQueueElement> mSortedRenderElements;
 		Vector<RenderQueueElement> mSortedRenderElements;
-		MaterialGrouping mGrouping;
+		StateReduction mStateReductionMode;
 	};
 	};
 }
 }

+ 6 - 6
BansheeEngine/Source/BsRenderQueue.cpp

@@ -9,8 +9,8 @@ using namespace std::placeholders;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	RenderQueue::RenderQueue(MaterialGrouping grouping)
-		:mGrouping(grouping)
+	RenderQueue::RenderQueue(StateReduction mode)
+		:mStateReductionMode(mode)
 	{
 	{
 
 
 	}
 	}
@@ -70,15 +70,15 @@ namespace BansheeEngine
 	{
 	{
 		std::function<bool(UINT32, UINT32, const Vector<SortableElement>&)> sortMethod;
 		std::function<bool(UINT32, UINT32, const Vector<SortableElement>&)> sortMethod;
 
 
-		switch (mGrouping)
+		switch (mStateReductionMode)
 		{
 		{
-		case MaterialGrouping::None:
+		case StateReduction::None:
 			sortMethod = &elementSorterNoGroup;
 			sortMethod = &elementSorterNoGroup;
 			break;
 			break;
-		case MaterialGrouping::PreferMaterial:
+		case StateReduction::Material:
 			sortMethod = &elementSorterPreferGroup;
 			sortMethod = &elementSorterPreferGroup;
 			break;
 			break;
-		case MaterialGrouping::PreferSortType:
+		case StateReduction::Distance:
 			sortMethod = &elementSorterPreferSort;
 			sortMethod = &elementSorterPreferSort;
 			break;
 			break;
 		}
 		}

+ 13 - 5
RenderBeast/Include/BsRenderBeast.h

@@ -217,13 +217,21 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Activates the specified pass on the pipeline.
 		 * @brief	Activates the specified pass on the pipeline.
 		 *
 		 *
-		 * @param	material			Parent material of the pass.
-		 * @param	passIdx				Index of the pass in the parent material.
-		 * @param	samplerOverrides	Optional samplers to use instead of the those in the material.
-		 *								Number of samplers must match the number in the material.
+		 * @param	pass			Pass to activate.
+		 * 
 		 * @note	Core thread.
 		 * @note	Core thread.
 		 */
 		 */
-		static void setPass(const SPtr<MaterialCore>& material, UINT32 passIdx, PassSamplerOverrides* samplerOverrides);
+		static void setPass(const SPtr<PassCore>& pass);
+
+		/**
+		 * @brief	Sets parameters (textures, samplers, buffers) for the currently active pass.
+		 *
+		 * @param	passParams			Structure containing parameters for all stages of the pass.
+		 * @param	samplerOverrides	Optional samplers to use instead of the those in the pass parameters.
+		 *								Number of samplers must match number in pass parameters.						
+		 * @note	Core thread.
+		 */
+		static void setPassParams(const SPtr<PassParametersCore>& passParams, const PassSamplerOverrides* samplerOverrides);
 
 
 		Vector<RenderTargetData> mRenderTargets; // Core thread
 		Vector<RenderTargetData> mRenderTargets; // Core thread
 		UnorderedMap<const CameraCore*, CameraData> mCameraData; // Core thread
 		UnorderedMap<const CameraCore*, CameraData> mCameraData; // Core thread

+ 8 - 0
RenderBeast/Include/BsRenderBeastOptions.h

@@ -2,6 +2,7 @@
 
 
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderer.h"
 #include "BsRenderer.h"
+#include "BsRenderQueue.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -52,5 +53,12 @@ namespace BansheeEngine
 		 * on average scene brightness.
 		 * on average scene brightness.
 		 */
 		 */
 		bool hdr = true;
 		bool hdr = true;
+
+		/**
+		 * Controls if and how a render queue groups renderable objects by material in 
+		 * order to reduce number of state changes. Sorting by material can reduce CPU usage
+		 * but could increase overdraw.
+		 */
+		StateReduction stateReductionMode = StateReduction::Distance;
 	};
 	};
 }
 }

+ 153 - 139
RenderBeast/Source/BsRenderBeast.cpp

@@ -244,8 +244,13 @@ namespace BansheeEngine
 	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
 	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
 	{
 	{
 		CameraData& camData = mCameraData[camera];
 		CameraData& camData = mCameraData[camera];
-		camData.opaqueQueue = bs_shared_ptr_new<RenderQueue>();
-		camData.transparentQueue = bs_shared_ptr_new<RenderQueue>();
+		camData.opaqueQueue = bs_shared_ptr_new<RenderQueue>(mCoreOptions->stateReductionMode);
+
+		StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
+		if (transparentStateReduction == StateReduction::Material)
+			transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
+
+		camData.transparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
 	}
 	}
 
 
 	void RenderBeast::_notifyCameraRemoved(const CameraCore* camera)
 	void RenderBeast::_notifyCameraRemoved(const CameraCore* camera)
@@ -288,6 +293,17 @@ namespace BansheeEngine
 			refreshSamplerOverrides(true);
 			refreshSamplerOverrides(true);
 
 
 		*mCoreOptions = options;
 		*mCoreOptions = options;
+
+		for (auto& cameraData : mCameraData)
+		{
+			cameraData.second.opaqueQueue->setStateReduction(mCoreOptions->stateReductionMode);
+
+			StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
+			if (transparentStateReduction == StateReduction::Material)
+				transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
+
+			cameraData.second.transparentQueue->setStateReduction(transparentStateReduction);
+		}
 	}
 	}
 
 
 	void RenderBeast::renderAllCore(float time)
 	void RenderBeast::renderAllCore(float time)
@@ -465,47 +481,43 @@ namespace BansheeEngine
 		const Vector<RenderQueueElement>& opaqueElements = cameraData.opaqueQueue->getSortedElements();
 		const Vector<RenderQueueElement>& opaqueElements = cameraData.opaqueQueue->getSortedElements();
 		for(auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		for(auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		{
 		{
-			SPtr<MaterialCore> material = iter->renderElem->material;
-
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			if (renderElem != nullptr)
-			{
-				UINT32 rendererId = renderElem->renderableId;
-				const RenderableData& renderableData = mRenderables[rendererId];
+			SPtr<MaterialCore> material = renderElem->material;
 
 
-				RenderableCore* renderable = renderableData.renderable;
-				RenderableController* controller = renderableData.controller;
-				UINT32 renderableType = renderable->getRenderableType();
-				
-				if (controller != nullptr)
-					controller->bindPerObjectBuffers(*renderElem);
+			UINT32 rendererId = renderElem->renderableId;
+			Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
 
 
-				if (renderableType == RenType_LitTextured)
+			mLitTexHandler->bindPerObjectBuffers(*renderElem);
+			mLitTexHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+
+			// TODO - Updating material buffers here is wrong - especially once per pass since elements are interated per-pass already
+			UINT32 numPasses = renderElem->material->getNumPasses();
+			for (UINT32 i = 0; i < numPasses; i++)
+			{
+				SPtr<PassParametersCore> passParams = renderElem->material->getPassParameters(i);
+
+				for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
 				{
 				{
-					Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
-					mLitTexHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+					SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
+					if (params != nullptr)
+						params->updateHardwareBuffers();
 				}
 				}
+			}
 
 
-				UINT32 numPasses = renderElem->material->getNumPasses();
-				for (UINT32 i = 0; i < numPasses; i++)
-				{
-					SPtr<PassParametersCore> passParams = renderElem->material->getPassParameters(i);
+			if (iter->applyPass)
+			{
+				SPtr<PassCore> pass = material->getPass(iter->passIdx);
+				setPass(pass);
+			}
 
 
-					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
-					{
-						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
-						if (params != nullptr)
-							params->updateHardwareBuffers();
-					}
-				}
-				
-				if (renderElem != nullptr && renderElem->samplerOverrides != nullptr)
-					setPass(material, iter->passIdx, &renderElem->samplerOverrides->passes[iter->passIdx]);
+			{
+				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+
+				if (renderElem->samplerOverrides != nullptr)
+					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
 				else
 				else
-					setPass(material, iter->passIdx, nullptr);
+					setPassParams(passParams, nullptr);
 			}
 			}
-			else
-				setPass(material, iter->passIdx, nullptr);
 
 
 			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 		}
 		}
@@ -514,47 +526,43 @@ namespace BansheeEngine
 		const Vector<RenderQueueElement>& transparentElements = cameraData.transparentQueue->getSortedElements();
 		const Vector<RenderQueueElement>& transparentElements = cameraData.transparentQueue->getSortedElements();
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		{
 		{
-			SPtr<MaterialCore> material = iter->renderElem->material;
-
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			if (renderElem != nullptr)
-			{
-				UINT32 rendererId = renderElem->renderableId;
-				const RenderableData& renderableData = mRenderables[rendererId];
+			SPtr<MaterialCore> material = renderElem->material;
+
+			UINT32 rendererId = renderElem->renderableId;
+			Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
 
 
-				RenderableCore* renderable = renderableData.renderable;
-				RenderableController* controller = renderableData.controller;
-				UINT32 renderableType = renderable->getRenderableType();
+			mLitTexHandler->bindPerObjectBuffers(*renderElem);
+			mLitTexHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
 
 
-				if (controller != nullptr)
-					controller->bindPerObjectBuffers(*renderElem);
+			// TODO - Updating material buffers here is wrong - especially once per pass since elements are interated per-pass already
+			UINT32 numPasses = renderElem->material->getNumPasses();
+			for (UINT32 i = 0; i < numPasses; i++)
+			{
+				SPtr<PassParametersCore> passParams = material->getPassParameters(i);
 
 
-				if (renderableType == RenType_LitTextured)
+				for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
 				{
 				{
-					Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
-					mLitTexHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+					SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
+					if (params != nullptr)
+						params->updateHardwareBuffers();
 				}
 				}
+			}
 
 
-				UINT32 numPasses = renderElem->material->getNumPasses();
-				for (UINT32 i = 0; i < numPasses; i++)
-				{
-					SPtr<PassParametersCore> passParams = renderElem->material->getPassParameters(i);
+			if (iter->applyPass)
+			{
+				SPtr<PassCore> pass = material->getPass(iter->passIdx);
+				setPass(pass);
+			}
 
 
-					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
-					{
-						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
-						if (params != nullptr)
-							params->updateHardwareBuffers();
-					}
-				}
+			{
+				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
 
 
-				if (renderElem != nullptr && renderElem->samplerOverrides != nullptr)
-					setPass(material, iter->passIdx, &renderElem->samplerOverrides->passes[iter->passIdx]);
+				if (renderElem->samplerOverrides != nullptr)
+					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
 				else
 				else
-					setPass(material, iter->passIdx, nullptr);
+					setPassParams(passParams, nullptr);
 			}
 			}
-			else
-				setPass(material, iter->passIdx, nullptr);
 
 
 			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 		}
 		}
@@ -628,50 +636,28 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void RenderBeast::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx, PassSamplerOverrides* samplerOverrides)
+	void RenderBeast::setPass(const SPtr<PassCore>& pass)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
 		RenderAPICore& rs = RenderAPICore::instance();
 		RenderAPICore& rs = RenderAPICore::instance();
 
 
-		SPtr<PassCore> pass = material->getPass(passIdx);
-		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
-
 		struct StageData
 		struct StageData
 		{
 		{
 			GpuProgramType type;
 			GpuProgramType type;
 			bool enable;
 			bool enable;
-			SPtr<GpuParamsCore> params;
 			SPtr<GpuProgramCore> program;
 			SPtr<GpuProgramCore> program;
 		};
 		};
 
 
 		const UINT32 numStages = 6;
 		const UINT32 numStages = 6;
 		StageData stages[numStages] =
 		StageData stages[numStages] =
 		{
 		{
-			{
-				GPT_VERTEX_PROGRAM, pass->hasVertexProgram(),
-				passParams->mVertParams, pass->getVertexProgram()
-			},
-			{
-				GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(),
-				passParams->mFragParams, pass->getFragmentProgram()
-			},
-			{
-				GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(),
-				passParams->mGeomParams, pass->getGeometryProgram()
-			},
-			{
-				GPT_HULL_PROGRAM, pass->hasHullProgram(),
-				passParams->mHullParams, pass->getHullProgram()
-			},
-			{
-				GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(),
-				passParams->mDomainParams, pass->getDomainProgram()
-			},
-			{
-				GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(),
-				passParams->mComputeParams, pass->getComputeProgram()
-			}
+			{ GPT_VERTEX_PROGRAM, pass->hasVertexProgram(), pass->getVertexProgram() },
+			{ GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(), pass->getFragmentProgram() },
+			{ GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(), pass->getGeometryProgram() },
+			{ GPT_HULL_PROGRAM, pass->hasHullProgram(), pass->getHullProgram() },
+			{ GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(), pass->getDomainProgram() },
+			{ GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(), pass->getComputeProgram() }
 		};
 		};
 
 
 		for (UINT32 i = 0; i < numStages; i++)
 		for (UINT32 i = 0; i < numStages; i++)
@@ -679,57 +665,11 @@ namespace BansheeEngine
 			const StageData& stage = stages[i];
 			const StageData& stage = stages[i];
 
 
 			if (stage.enable)
 			if (stage.enable)
-			{
 				rs.bindGpuProgram(stage.program);
 				rs.bindGpuProgram(stage.program);
-
-				SPtr<GpuParamsCore> params = stage.params;
-				const GpuParamDesc& paramDesc = params->getParamDesc();
-
-				for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-				{
-					SPtr<SamplerStateCore> samplerState;
-						
-					if (samplerOverrides != nullptr)
-						samplerState = samplerOverrides->stages[i].stateOverrides[iter->second.slot];
-					else
-						samplerState = params->getSamplerState(iter->second.slot);
-
-					if (samplerState == nullptr)
-						rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault());
-					else
-						rs.setSamplerState(stage.type, iter->second.slot, samplerState);
-				}
-
-				for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
-				{
-					SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
-
-					if (!params->isLoadStoreTexture(iter->second.slot))
-					{
-						if (texture == nullptr)
-							rs.setTexture(stage.type, iter->second.slot, false, nullptr);
-						else
-							rs.setTexture(stage.type, iter->second.slot, true, texture);
-					}
-					else
-					{
-						const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
-
-						if (texture == nullptr)
-							rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
-						else
-							rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
-					}
-				}
-
-				rs.setConstantBuffers(stage.type, params);
-			}
 			else
 			else
 				rs.unbindGpuProgram(stage.type);
 				rs.unbindGpuProgram(stage.type);
 		}
 		}
 
 
-		// TODO - Try to limit amount of state changes, if previous state is already the same
-
 		// Set up non-texture related pass settings
 		// Set up non-texture related pass settings
 		if (pass->getBlendState() != nullptr)
 		if (pass->getBlendState() != nullptr)
 			rs.setBlendState(pass->getBlendState());
 			rs.setBlendState(pass->getBlendState());
@@ -747,6 +687,80 @@ namespace BansheeEngine
 			rs.setRasterizerState(RasterizerStateCore::getDefault());
 			rs.setRasterizerState(RasterizerStateCore::getDefault());
 	}
 	}
 
 
+	void RenderBeast::setPassParams(const SPtr<PassParametersCore>& passParams, const PassSamplerOverrides* samplerOverrides)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		struct StageData
+		{
+			GpuProgramType type;
+			SPtr<GpuParamsCore> params;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
+		{
+			{ GPT_VERTEX_PROGRAM, passParams->mVertParams },
+			{ GPT_FRAGMENT_PROGRAM, passParams->mFragParams },
+			{ GPT_GEOMETRY_PROGRAM, passParams->mGeomParams },
+			{ GPT_HULL_PROGRAM, passParams->mHullParams },
+			{ GPT_DOMAIN_PROGRAM, passParams->mDomainParams },
+			{ GPT_COMPUTE_PROGRAM, passParams->mComputeParams }
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			SPtr<GpuParamsCore> params = stage.params;
+			if (params == nullptr)
+				continue;
+
+			const GpuParamDesc& paramDesc = params->getParamDesc();
+
+			for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
+			{
+				SPtr<SamplerStateCore> samplerState;
+
+				if (samplerOverrides != nullptr)
+					samplerState = samplerOverrides->stages[i].stateOverrides[iter->second.slot];
+				else
+					samplerState = params->getSamplerState(iter->second.slot);
+
+				if (samplerState == nullptr)
+					rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault());
+				else
+					rs.setSamplerState(stage.type, iter->second.slot, samplerState);
+			}
+
+			for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
+			{
+				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
+
+				if (!params->isLoadStoreTexture(iter->second.slot))
+				{
+					if (texture == nullptr)
+						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
+					else
+						rs.setTexture(stage.type, iter->second.slot, true, texture);
+				}
+				else
+				{
+					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+					if (texture == nullptr)
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
+					else
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
+				}
+			}
+
+			rs.setConstantBuffers(stage.type, params);
+		}
+	}
+
 	SPtr<ShaderCore> RenderBeast::createDefaultShader()
 	SPtr<ShaderCore> RenderBeast::createDefaultShader()
 	{
 	{
 		StringID rsName = RenderAPICore::instance().getName();
 		StringID rsName = RenderAPICore::instance().getName();