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

Sampler state filtering overrides (WIP)
Render options for renderer
Hashes & caching for render states (untested)

Marko Pintera 10 лет назад
Родитель
Сommit
aec99b0b0f
38 измененных файлов с 1136 добавлено и 262 удалено
  1. 33 5
      BansheeCore/Include/BsBlendState.h
  2. 5 5
      BansheeCore/Include/BsBlendStateRTTI.h
  3. 5 0
      BansheeCore/Include/BsCommonTypes.h
  4. 19 0
      BansheeCore/Include/BsCoreRenderer.h
  5. 32 5
      BansheeCore/Include/BsDepthStencilState.h
  6. 5 5
      BansheeCore/Include/BsDepthStencilStateRTTI.h
  7. 1 1
      BansheeCore/Include/BsGpuParams.h
  8. 31 5
      BansheeCore/Include/BsRasterizerState.h
  9. 5 5
      BansheeCore/Include/BsRasterizerStateRTTI.h
  10. 13 4
      BansheeCore/Include/BsRenderAPI.h
  11. 144 18
      BansheeCore/Include/BsRenderStateManager.h
  12. 31 5
      BansheeCore/Include/BsSamplerState.h
  13. 5 5
      BansheeCore/Include/BsSamplerStateRTTI.h
  14. 60 1
      BansheeCore/Source/BsBlendState.cpp
  15. 47 40
      BansheeCore/Source/BsCoreRenderer.cpp
  16. 50 1
      BansheeCore/Source/BsDepthStencilState.cpp
  17. 40 1
      BansheeCore/Source/BsRasterizerState.cpp
  18. 46 2
      BansheeCore/Source/BsRenderAPI.cpp
  19. 199 36
      BansheeCore/Source/BsRenderStateManager.cpp
  20. 44 1
      BansheeCore/Source/BsSamplerState.cpp
  21. 2 2
      BansheeD3D11RenderSystem/Include/BsD3D11RenderAPI.h
  22. 2 37
      BansheeD3D11RenderSystem/Source/BsD3D11RenderAPI.cpp
  23. 2 2
      BansheeD3D9RenderSystem/Include/BsD3D9RenderAPI.h
  24. 1 22
      BansheeD3D9RenderSystem/Source/BsD3D9RenderAPI.cpp
  25. 2 2
      BansheeEditor/Source/BsGizmoManager.cpp
  26. 4 4
      BansheeEditor/Source/BsScenePicking.cpp
  27. 8 1
      BansheeEngine/Include/BsRenderableElement.h
  28. 2 2
      BansheeGLRenderSystem/Include/BsGLRenderAPI.h
  29. 6 35
      BansheeGLRenderSystem/Source/BsGLRenderAPI.cpp
  30. 1 0
      BansheeRenderer/BansheeRenderer.vcxproj
  31. 3 0
      BansheeRenderer/BansheeRenderer.vcxproj.filters
  32. 34 1
      BansheeRenderer/Include/BsBansheeRenderer.h
  33. 1 0
      BansheeRenderer/Include/BsBansheeRendererPrerequisites.h
  34. 56 0
      BansheeRenderer/Include/BsRenderBeastOptions.h
  35. 166 1
      BansheeRenderer/Source/BsBansheeRenderer.cpp
  36. 18 0
      BansheeUtility/Include/BsColor.h
  37. 1 1
      BansheeUtility/Include/BsString.h
  38. 12 7
      TODOExperimentation.txt

+ 33 - 5
BansheeCore/Include/BsBlendState.h

@@ -25,6 +25,8 @@ namespace BansheeEngine
 			, renderTargetWriteMask(0xFF)
 			, renderTargetWriteMask(0xFF)
 		{ }
 		{ }
 
 
+		bool operator==(const RENDER_TARGET_BLEND_STATE_DESC& rhs) const;
+
 		bool blendEnable;
 		bool blendEnable;
 		BlendFactor srcBlend;
 		BlendFactor srcBlend;
 		BlendFactor dstBlend;
 		BlendFactor dstBlend;
@@ -49,6 +51,8 @@ namespace BansheeEngine
 			, independantBlendEnable(false)
 			, independantBlendEnable(false)
 		{ }
 		{ }
 
 
+		bool operator==(const BLEND_STATE_DESC& rhs) const;
+
 		bool alphaToCoverageEnable;
 		bool alphaToCoverageEnable;
 		bool independantBlendEnable;
 		bool independantBlendEnable;
 		RENDER_TARGET_BLEND_STATE_DESC renderTargetDesc[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		RENDER_TARGET_BLEND_STATE_DESC renderTargetDesc[BS_MAX_MULTIPLE_RENDER_TARGETS];
@@ -133,11 +137,18 @@ namespace BansheeEngine
 		 */
 		 */
 		UINT8 getRenderTargetWriteMask(UINT32 renderTargetIdx) const;
 		UINT8 getRenderTargetWriteMask(UINT32 renderTargetIdx) const;
 
 
+		/**
+		 * @brief	Returns the hash value generated from the blend state properties.
+		 */
+		UINT64 getHash() const { return mHash; }
+
 	protected:
 	protected:
 		friend class BlendState;
 		friend class BlendState;
+		friend class BlendStateCore;
 		friend class BlendStateRTTI;
 		friend class BlendStateRTTI;
 
 
 		BLEND_STATE_DESC mData;
 		BLEND_STATE_DESC mData;
+		UINT64 mHash;
 	};
 	};
 
 
 /**
 /**
@@ -150,7 +161,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT BlendStateCore : public CoreObjectCore
 	class BS_CORE_EXPORT BlendStateCore : public CoreObjectCore
 	{
 	{
 	public:
 	public:
-		virtual ~BlendStateCore() {}
+		virtual ~BlendStateCore();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the blend state.
 		 * @brief	Returns information about the blend state.
@@ -181,7 +192,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT BlendState : public IReflectable, public CoreObject
 	class BS_CORE_EXPORT BlendState : public IReflectable, public CoreObject
 	{
 	{
 	public:
 	public:
-		virtual ~BlendState() {}
+		virtual ~BlendState();
 
 
 		/**
 		/**
 		 * @brief	Returns information about a blend state.
 		 * @brief	Returns information about a blend state.
@@ -205,6 +216,11 @@ namespace BansheeEngine
 		 */
 		 */
 		static const BlendStatePtr& getDefault();
 		static const BlendStatePtr& getDefault();
 
 
+		/**
+		 * @brief	Generates a hash value from a blend state descriptor.
+		 */
+		static UINT64 generateHash(const BLEND_STATE_DESC& desc);
+
 	protected:
 	protected:
 		friend class RenderStateManager;
 		friend class RenderStateManager;
 
 
@@ -213,7 +229,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @copydoc	CoreObjectCore::createCore
 		 * @copydoc	CoreObjectCore::createCore
 		 */
 		 */
-		SPtr<CoreObjectCore> createCore() const;
+		SPtr<CoreObjectCore> createCore() const override;
 
 
 		BlendProperties mProperties;
 		BlendProperties mProperties;
 
 
@@ -224,6 +240,18 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class BlendStateRTTI;
 		friend class BlendStateRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;	
+		virtual RTTITypeBase* getRTTI() const override;	
 	};
 	};
-}
+}
+
+/**
+ * @brief	Hash value generator for BLEND_STATE_DESC.
+ */
+template<>
+struct std::hash<BansheeEngine::BLEND_STATE_DESC>
+{
+	size_t operator()(const BansheeEngine::BLEND_STATE_DESC& value) const
+	{
+		return (size_t)BansheeEngine::BlendState::generateHash(value);
+	}
+};

+ 5 - 5
BansheeCore/Include/BsBlendStateRTTI.h

@@ -60,26 +60,26 @@ namespace BansheeEngine
 			addPlainField("mData", 0, &BlendStateRTTI::getData, &BlendStateRTTI::setData);
 			addPlainField("mData", 0, &BlendStateRTTI::getData, &BlendStateRTTI::setData);
 		}
 		}
 
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj) override
 		{
 		{
 			BlendState* blendState = static_cast<BlendState*>(obj);
 			BlendState* blendState = static_cast<BlendState*>(obj);
 			blendState->initialize();
 			blendState->initialize();
 		}
 		}
 
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "BlendState";
 			static String name = "BlendState";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_BlendState;
 			return TID_BlendState;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
-			return RenderStateManager::instance().createEmptyBlendState();
+			return RenderStateManager::instance()._createBlendStatePtr(BLEND_STATE_DESC());
 		}
 		}
 	};
 	};
 }
 }

+ 5 - 0
BansheeCore/Include/BsCommonTypes.h

@@ -329,6 +329,11 @@ namespace BansheeEngine
 			:u(TAM_WRAP), v(TAM_WRAP), w(TAM_WRAP)
 			:u(TAM_WRAP), v(TAM_WRAP), w(TAM_WRAP)
 		{ }
 		{ }
 
 
+		bool operator==(const UVWAddressingMode& rhs) const
+		{
+			return u == rhs.u && v == rhs.v && w == rhs.w;
+		}
+
 		TextureAddressingMode u, v, w;
 		TextureAddressingMode u, v, w;
 	};
 	};
 
 

+ 19 - 0
BansheeCore/Include/BsCoreRenderer.h

@@ -29,6 +29,14 @@ namespace BansheeEngine
 	static StringID RPS_Diffuse = "Diffuse";
 	static StringID RPS_Diffuse = "Diffuse";
 	static StringID RPS_ViewDir = "ViewDir";
 	static StringID RPS_ViewDir = "ViewDir";
 
 
+	/**
+	 * @brief	Set of options that can be used for controlling the renderer.
+	 */	
+	struct BS_CORE_EXPORT CoreRendererOptions
+	{
+		virtual ~CoreRendererOptions() { }
+	};
+
 	/**
 	/**
 	 * @brief	Primarily rendering class that allows you to specify how to render objects that exist
 	 * @brief	Primarily rendering class that allows you to specify how to render objects that exist
 	 *			in the scene graph. You need to provide your own implementation of your class.
 	 *			in the scene graph. You need to provide your own implementation of your class.
@@ -39,6 +47,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT CoreRenderer
 	class BS_CORE_EXPORT CoreRenderer
 	{
 	{
 	public:
 	public:
+		CoreRenderer();
 		virtual ~CoreRenderer() { }
 		virtual ~CoreRenderer() { }
 
 
 		/**
 		/**
@@ -117,6 +126,16 @@ namespace BansheeEngine
 		 */
 		 */
 		void _unregisterRenderCallback(const CameraHandlerCore* camera, INT32 index);
 		void _unregisterRenderCallback(const CameraHandlerCore* camera, INT32 index);
 
 
+		/**
+		 * @brief	Sets options used for controlling the rendering.
+		 */
+		virtual void setOptions(const SPtr<CoreRendererOptions>& options) { }
+
+		/**
+		 * @brief	Returns current set of options used for controlling the rendering.
+		 */
+		virtual SPtr<CoreRendererOptions> getOptions() const { return SPtr<CoreRendererOptions>(); }
+
 		/**
 		/**
 		 * @brief	Activates the specified pass on the pipeline.
 		 * @brief	Activates the specified pass on the pipeline.
 		 *
 		 *

+ 32 - 5
BansheeCore/Include/BsDepthStencilState.h

@@ -30,6 +30,8 @@ namespace BansheeEngine
 			, backStencilComparisonFunc(CMPF_ALWAYS_PASS)
 			, backStencilComparisonFunc(CMPF_ALWAYS_PASS)
 		{ }
 		{ }
 
 
+		bool operator==(const DEPTH_STENCIL_STATE_DESC& rhs) const;
+
 		bool depthReadEnable;
 		bool depthReadEnable;
 		bool depthWriteEnable;
 		bool depthWriteEnable;
 		CompareFunction depthComparisonFunc;
 		CompareFunction depthComparisonFunc;
@@ -140,11 +142,18 @@ namespace BansheeEngine
 		*/
 		*/
 		CompareFunction getStencilBackCompFunc() const { return mData.backStencilComparisonFunc; }
 		CompareFunction getStencilBackCompFunc() const { return mData.backStencilComparisonFunc; }
 
 
+		/**
+		 * @brief	Returns the hash value generated from the depth-stencil state properties.
+		 */
+		UINT64 getHash() const { return mHash; }
+
 	protected:
 	protected:
 		friend class DepthStencilState;
 		friend class DepthStencilState;
+		friend class DepthStencilStateCore;
 		friend class DepthStencilStateRTTI;
 		friend class DepthStencilStateRTTI;
 
 
 		DEPTH_STENCIL_STATE_DESC mData;
 		DEPTH_STENCIL_STATE_DESC mData;
+		UINT64 mHash;
 	};
 	};
 
 
 	/**
 	/**
@@ -157,7 +166,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT DepthStencilStateCore : public CoreObjectCore
 	class BS_CORE_EXPORT DepthStencilStateCore : public CoreObjectCore
 	{
 	{
 	public:
 	public:
-		virtual ~DepthStencilStateCore() {}
+		virtual ~DepthStencilStateCore();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the depth stencil state.
 		 * @brief	Returns information about the depth stencil state.
@@ -187,7 +196,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT DepthStencilState : public IReflectable, public CoreObject
 	class BS_CORE_EXPORT DepthStencilState : public IReflectable, public CoreObject
 	{
 	{
 	public:
 	public:
-		virtual ~DepthStencilState() {}
+		virtual ~DepthStencilState();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the depth stencil state.
 		 * @brief	Returns information about the depth stencil state.
@@ -209,6 +218,12 @@ namespace BansheeEngine
 		 * @brief	Returns the default depth stencil state that you may use when no other is available.
 		 * @brief	Returns the default depth stencil state that you may use when no other is available.
 		 */
 		 */
 		static const DepthStencilStatePtr& getDefault();
 		static const DepthStencilStatePtr& getDefault();
+
+		/**
+		 * @brief	Generates a hash value from a depth-stencil state descriptor.
+		 */
+		static UINT64 generateHash(const DEPTH_STENCIL_STATE_DESC& desc);
+
 	protected:
 	protected:
 		friend class RenderStateManager;
 		friend class RenderStateManager;
 
 
@@ -217,7 +232,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @copydoc	CoreObjectCore::createCore
 		 * @copydoc	CoreObjectCore::createCore
 		 */
 		 */
-		SPtr<CoreObjectCore> createCore() const;
+		SPtr<CoreObjectCore> createCore() const override;
 
 
 		DepthStencilProperties mProperties;
 		DepthStencilProperties mProperties;
 
 
@@ -228,6 +243,18 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class DepthStencilStateRTTI;
 		friend class DepthStencilStateRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;	
+		virtual RTTITypeBase* getRTTI() const override;	
 	};
 	};
-}
+}
+
+/**
+ * @brief	Hash value generator for DEPTH_STENCIL_STATE_DESC.
+ */
+template<>
+struct std::hash<BansheeEngine::DEPTH_STENCIL_STATE_DESC>
+{
+	size_t operator()(const BansheeEngine::DEPTH_STENCIL_STATE_DESC& value) const
+	{
+		return (size_t)BansheeEngine::DepthStencilState::generateHash(value);
+	}
+};

+ 5 - 5
BansheeCore/Include/BsDepthStencilStateRTTI.h

@@ -19,26 +19,26 @@ namespace BansheeEngine
 			addPlainField("mData", 0, &DepthStencilStateRTTI::getData, &DepthStencilStateRTTI::setData);
 			addPlainField("mData", 0, &DepthStencilStateRTTI::getData, &DepthStencilStateRTTI::setData);
 		}
 		}
 
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj) override
 		{
 		{
 			DepthStencilState* depthStencilState = static_cast<DepthStencilState*>(obj);
 			DepthStencilState* depthStencilState = static_cast<DepthStencilState*>(obj);
 			depthStencilState->initialize();
 			depthStencilState->initialize();
 		}
 		}
 
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "DepthStencilState";
 			static String name = "DepthStencilState";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_DepthStencilState;
 			return TID_DepthStencilState;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
-			return RenderStateManager::instance().createEmptyDepthStencilState();
+			return RenderStateManager::instance()._createDepthStencilStatePtr(DEPTH_STENCIL_STATE_DESC());
 		}
 		}
 	};
 	};
 }
 }

+ 1 - 1
BansheeCore/Include/BsGpuParams.h

@@ -315,7 +315,7 @@ namespace BansheeEngine
 	 *			are stored internally on the CPU, and are only submitted to the GPU
 	 *			are stored internally on the CPU, and are only submitted to the GPU
 	 *			once the parameters are bound to the pipeline.
 	 *			once the parameters are bound to the pipeline.
 	 *
 	 *
-	 * @see		CoreThreadAccessor::bindGpuParams
+	 * @see		CoreThreadAccessor::setConstantBuffers
 	 *
 	 *
 	 * @note	Sim thread only.
 	 * @note	Sim thread only.
 	 */
 	 */

+ 31 - 5
BansheeCore/Include/BsRasterizerState.h

@@ -26,6 +26,8 @@ namespace BansheeEngine
 			, antialiasedLineEnable(false)
 			, antialiasedLineEnable(false)
 		{ }
 		{ }
 
 
+		bool operator==(const RASTERIZER_STATE_DESC& rhs) const;
+
 		PolygonMode polygonMode;
 		PolygonMode polygonMode;
 		CullingMode cullMode;
 		CullingMode cullMode;
 
 
@@ -115,11 +117,18 @@ namespace BansheeEngine
 		 */
 		 */
 		bool getAntialiasedLineEnable() const { return mData.antialiasedLineEnable; }
 		bool getAntialiasedLineEnable() const { return mData.antialiasedLineEnable; }
 
 
+		/**
+		 * @brief	Returns the hash value generated from the rasterizer state properties.
+		 */
+		UINT64 getHash() const { return mHash; }
+
 	protected:
 	protected:
 		friend class RasterizerState;
 		friend class RasterizerState;
+		friend class RasterizerStateCore;
 		friend class RasterizerStateRTTI;
 		friend class RasterizerStateRTTI;
 
 
 		RASTERIZER_STATE_DESC mData;
 		RASTERIZER_STATE_DESC mData;
+		UINT64 mHash;
 	};
 	};
 
 
 	/**
 	/**
@@ -132,7 +141,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT RasterizerStateCore : public CoreObjectCore
 	class BS_CORE_EXPORT RasterizerStateCore : public CoreObjectCore
 	{
 	{
 	public:
 	public:
-		virtual ~RasterizerStateCore() {}
+		virtual ~RasterizerStateCore();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the rasterizer state.
 		 * @brief	Returns information about the rasterizer state.
@@ -161,7 +170,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT RasterizerState : public IReflectable, public CoreObject
 	class BS_CORE_EXPORT RasterizerState : public IReflectable, public CoreObject
 	{
 	{
 	public:
 	public:
-		virtual ~RasterizerState() {}
+		virtual ~RasterizerState();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the rasterizer state.
 		 * @brief	Returns information about the rasterizer state.
@@ -184,6 +193,11 @@ namespace BansheeEngine
 		 */
 		 */
 		static const RasterizerStatePtr& getDefault();
 		static const RasterizerStatePtr& getDefault();
 
 
+		/**
+		 * @brief	Generates a hash value from a rasterizer state descriptor.
+		 */
+		static UINT64 generateHash(const RASTERIZER_STATE_DESC& desc);
+
 	protected:
 	protected:
 		friend class RenderStateManager;
 		friend class RenderStateManager;
 
 
@@ -192,7 +206,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @copydoc	CoreObjectCore::createCore
 		 * @copydoc	CoreObjectCore::createCore
 		 */
 		 */
-		SPtr<CoreObjectCore> createCore() const;
+		SPtr<CoreObjectCore> createCore() const override;
 
 
 		RasterizerProperties mProperties;
 		RasterizerProperties mProperties;
 
 
@@ -203,6 +217,18 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class RasterizerStateRTTI;
 		friend class RasterizerStateRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;	
+		virtual RTTITypeBase* getRTTI() const override;	
 	};
 	};
-}
+}
+
+/**
+ * @brief	Hash value generator for RASTERIZER_STATE_DESC.
+ */
+template<>
+struct std::hash<BansheeEngine::RASTERIZER_STATE_DESC>
+{
+	size_t operator()(const BansheeEngine::RASTERIZER_STATE_DESC& value) const
+	{
+		return (size_t)BansheeEngine::RasterizerState::generateHash(value);
+	}
+};

+ 5 - 5
BansheeCore/Include/BsRasterizerStateRTTI.h

@@ -21,26 +21,26 @@ namespace BansheeEngine
 			addPlainField("mData", 0, &RasterizerStateRTTI::getData, &RasterizerStateRTTI::setData);
 			addPlainField("mData", 0, &RasterizerStateRTTI::getData, &RasterizerStateRTTI::setData);
 		}
 		}
 
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj) override
 		{
 		{
 			RasterizerState* rasterizerState = static_cast<RasterizerState*>(obj);
 			RasterizerState* rasterizerState = static_cast<RasterizerState*>(obj);
 			rasterizerState->initialize();
 			rasterizerState->initialize();
 		}
 		}
 
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "RasterizerState";
 			static String name = "RasterizerState";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_RasterizerState;
 			return TID_RasterizerState;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
-			return RenderStateManager::instance().createEmptyRasterizerState();
+			return RenderStateManager::instance()._createRasterizerStatePtr(RASTERIZER_STATE_DESC());
 		}
 		}
 	};
 	};
 }
 }

+ 13 - 4
BansheeCore/Include/BsRenderAPI.h

@@ -88,8 +88,11 @@ namespace BansheeEngine
 		/** @copydoc RenderAPICore::unbindGpuProgram() */
 		/** @copydoc RenderAPICore::unbindGpuProgram() */
 		static void unbindGpuProgram(CoreAccessor& accessor, GpuProgramType gptype);
 		static void unbindGpuProgram(CoreAccessor& accessor, GpuProgramType gptype);
 
 
-		/** @copydoc RenderAPICore::bindGpuParams() */
-		static void bindGpuParams(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params);
+		/** @copydoc RenderAPICore::setConstantBuffers() */
+		static void setConstantBuffers(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params);
+
+		/** @copydoc RenderAPICore::setGpuParams() */
+		static void setGpuParams(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params);
 
 
 		/** @copydoc RenderAPICore::beginFrame() */
 		/** @copydoc RenderAPICore::beginFrame() */
 		static void beginRender(CoreAccessor& accessor);
 		static void beginRender(CoreAccessor& accessor);
@@ -294,10 +297,16 @@ namespace BansheeEngine
 		virtual void bindGpuProgram(const SPtr<GpuProgramCore>& prg);
 		virtual void bindGpuProgram(const SPtr<GpuProgramCore>& prg);
 
 
 		/**
 		/**
-		 * @brief	Binds GPU program parameters. Caller must ensure these match the previously
+		 * @brief	Binds constant(uniform) GPU program parameters. Caller must ensure these match the previously
+		 *			bound GPU program.
+		 */
+		virtual void setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& params) = 0;
+
+		/**
+		 * @brief	Binds all specified GPU program parameters. Caller must ensure these match the previously
 		 *			bound GPU program.
 		 *			bound GPU program.
 		 */
 		 */
-		virtual void bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params) = 0;
+		virtual void setGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
 
 
 		/**
 		/**
 		 * @brief	Unbinds a program of a given type. 
 		 * @brief	Unbinds a program of a given type. 

+ 144 - 18
BansheeCore/Include/BsRenderStateManager.h

@@ -2,13 +2,125 @@
 
 
 #include "BsCorePrerequisites.h"
 #include "BsCorePrerequisites.h"
 #include "BsModule.h"
 #include "BsModule.h"
+#include "BsBlendState.h"
+#include "BsRasterizerState.h"
+#include "BsDepthStencilState.h"
+#include "BsSamplerState.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	/**
+	 * @brief	Common methods and data for both sim and core thread versions
+	 *			of RenderStateManager.
+	 */
+	template<bool Core>
+	class BS_CORE_EXPORT TRenderStateManager
+	{
+	public:
+		virtual ~TRenderStateManager() { }
+
+	protected:
+		template<bool Core> struct TSamplerStateType { };
+		template<> struct TSamplerStateType < false > { typedef SamplerState Type; };
+		template<> struct TSamplerStateType < true > { typedef SamplerStateCore Type; };
+
+		template<bool Core> struct TBlendStateType { };
+		template<> struct TBlendStateType < false > { typedef BlendState Type; };
+		template<> struct TBlendStateType < true > { typedef BlendStateCore Type; };
+
+		template<bool Core> struct TRasterizerStateType { };
+		template<> struct TRasterizerStateType < false > { typedef RasterizerState Type; };
+		template<> struct TRasterizerStateType < true > { typedef RasterizerStateCore Type; };
+
+		template<bool Core> struct TDepthStencilStateType { };
+		template<> struct TDepthStencilStateType < false > { typedef DepthStencilState Type; };
+		template<> struct TDepthStencilStateType < true > { typedef DepthStencilStateCore Type; };
+
+		typedef typename TSamplerStateType<Core>::Type SamplerStateType;
+		typedef typename TBlendStateType<Core>::Type BlendStateType;
+		typedef typename TRasterizerStateType<Core>::Type RasterizerStateType;
+		typedef typename TDepthStencilStateType<Core>::Type DepthStencilStateType;
+
+		/**
+		 * @brief	Triggered when a new sampler state is created. 
+		 */
+		void notifySamplerStateCreated(const SAMPLER_STATE_DESC& desc, const SPtr<SamplerStateType>& state) const;
+
+		/**
+		 * @brief	Triggered when a new sampler state is created. 
+		 */
+		void notifyBlendStateCreated(const BLEND_STATE_DESC& desc, const SPtr<BlendStateType>& state) const;
+
+		/**
+		 * @brief	Triggered when a new sampler state is created. 
+		 */
+		void notifyRasterizerStateCreated(const RASTERIZER_STATE_DESC& desc, const SPtr<RasterizerStateType>& state) const;
+
+		/**
+		 * @brief	Triggered when a new sampler state is created. 
+		 */
+		void notifyDepthStencilStateCreated(const DEPTH_STENCIL_STATE_DESC& desc, const SPtr<DepthStencilStateType>& state) const;
+
+		/**
+		 * @brief	Triggered when the last reference to a specific sampler state is destroyed, which
+		 *			means we must clear our cached version as well.
+		 */
+		void notifySamplerStateDestroyed(const SAMPLER_STATE_DESC& desc) const;
+
+		/**
+		 * @brief	Triggered when the last reference to a specific blend state is destroyed, which
+		 *			means we must clear our cached version as well.
+		 */
+		void notifyBlendStateDestroyed(const BLEND_STATE_DESC& desc) const;
+
+		/**
+		 * @brief	Triggered when the last reference to a specific rasterizer state is destroyed, which
+		 *			means we must clear our cached version as well.
+		 */
+		void notifyRasterizerStateDestroyed(const RASTERIZER_STATE_DESC& desc) const;
+
+		/**
+		 * @brief	Triggered when the last reference to a specific depth stencil state is destroyed, which
+		 *			means we must clear our cached version as well.
+		 */
+		void notifyDepthStencilStateDestroyed(const DEPTH_STENCIL_STATE_DESC& desc) const;
+
+		/**
+		 * @brief	Attempts to find a cached sampler state corresponding to the provided descriptor. 
+		 *			Returns null if one doesn't exist.
+		 */
+		SPtr<SamplerStateType> findCachedState(const SAMPLER_STATE_DESC& desc) const;
+
+				/**
+		 * @brief	Attempts to find a cached blend state corresponding to the provided descriptor. 
+		 *			Returns null if one doesn't exist.
+		 */
+		SPtr<BlendStateType> findCachedState(const BLEND_STATE_DESC& desc) const;
+
+				/**
+		 * @brief	Attempts to find a cached rasterizer state corresponding to the provided descriptor. 
+		 *			Returns null if one doesn't exist.
+		 */
+		SPtr<RasterizerStateType> findCachedState(const RASTERIZER_STATE_DESC& desc) const;
+
+		/**
+		 * @brief	Attempts to find a cached depth-stencil state corresponding to the provided descriptor. 
+		 *			Returns null if one doesn't exist.
+		 */
+		SPtr<DepthStencilStateType> findCachedState(const DEPTH_STENCIL_STATE_DESC& desc) const;
+
+		mutable UnorderedMap<SAMPLER_STATE_DESC, std::weak_ptr<SamplerStateType>> mCachedSamplerStates;
+		mutable UnorderedMap<BLEND_STATE_DESC, std::weak_ptr<BlendStateType>> mCachedBlendStates;
+		mutable UnorderedMap<RASTERIZER_STATE_DESC, std::weak_ptr<RasterizerStateType>> mCachedRasterizerStates;
+		mutable UnorderedMap<DEPTH_STENCIL_STATE_DESC, std::weak_ptr<DepthStencilStateType>> mCachedDepthStencilStates;
+
+		BS_MUTEX(mMutex);
+	};
+
 	/**
 	/**
 	 * @brief	Handles creation of various render states.
 	 * @brief	Handles creation of various render states.
 	 */
 	 */
-	class BS_CORE_EXPORT RenderStateManager : public Module <RenderStateManager>
+	class BS_CORE_EXPORT RenderStateManager : public Module <RenderStateManager>, TRenderStateManager<false>
 	{
 	{
 	public:
 	public:
 		/**
 		/**
@@ -32,32 +144,36 @@ namespace BansheeEngine
 		BlendStatePtr createBlendState(const BLEND_STATE_DESC& desc) const;
 		BlendStatePtr createBlendState(const BLEND_STATE_DESC& desc) const;
 
 
 		/**
 		/**
-		 * @brief	Creates a completely empty and uninitialized SamplerState.
-		 * 			Should only be used for VERY specific purposes, like deserialization,
-		 * 			as it requires additional manual initialization that is not required normally.
+		 * @brief	Creates an uninitialized sampler state. Requires manual initialization
+		 *			after creation.
+		 *
+		 * @note	Internal method.
 		 */
 		 */
-		SamplerStatePtr createEmptySamplerState() const;
+		SamplerStatePtr _createSamplerStatePtr(const SAMPLER_STATE_DESC& desc) const;
 
 
 		/**
 		/**
-		 * @brief	Creates a completely empty and uninitialized DepthStencilState.
-		 * 			Should only be used for VERY specific purposes, like deserialization,
-		 * 			as it requires additional manual initialization that is not required normally.
+		 * @brief	Creates an uninitialized depth-stencil state. Requires manual initialization
+		 *			after creation.
+		 *
+		 * @note	Internal method.
 		 */
 		 */
-		DepthStencilStatePtr createEmptyDepthStencilState() const;
+		DepthStencilStatePtr _createDepthStencilStatePtr(const DEPTH_STENCIL_STATE_DESC& desc) const;
 
 
 		/**
 		/**
-		 * @brief	Creates a completely empty and uninitialized RasterizerState.
-		 * 			Should only be used for VERY specific purposes, like deserialization,
-		 * 			as it requires additional manual initialization that is not required normally.
+		 * @brief	Creates an uninitialized rasterizer state. Requires manual initialization
+		 *			after creation.
+		 *
+		 * @note	Internal method.
 		 */
 		 */
-		RasterizerStatePtr createEmptyRasterizerState() const;
+		RasterizerStatePtr _createRasterizerStatePtr(const RASTERIZER_STATE_DESC& desc) const;
 
 
 		/**
 		/**
-		 * @brief	Creates a completely empty and uninitialized BlendState.
-		 * 			Should only be used for VERY specific purposes, like deserialization,
-		 * 			as it requires additional manual initialization that is not required normally.
+		 * @brief	Creates an uninitialized blend state. Requires manual initialization
+		 *			after creation.
+		 *
+		 * @note	Internal method.
 		 */
 		 */
-		BlendStatePtr createEmptyBlendState() const;
+		BlendStatePtr _createBlendStatePtr(const BLEND_STATE_DESC& desc) const;
 
 
 		/**
 		/**
 		 * @brief	Gets a sampler state initialized with default options.
 		 * @brief	Gets a sampler state initialized with default options.
@@ -80,6 +196,11 @@ namespace BansheeEngine
 		const DepthStencilStatePtr& getDefaultDepthStencilState() const;
 		const DepthStencilStatePtr& getDefaultDepthStencilState() const;
 
 
 	private:
 	private:
+		friend class SamplerState;
+		friend class BlendState;
+		friend class RasterizerState;
+		friend class DepthStencilState;
+
 		mutable SamplerStatePtr mDefaultSamplerState;
 		mutable SamplerStatePtr mDefaultSamplerState;
 		mutable BlendStatePtr mDefaultBlendState;
 		mutable BlendStatePtr mDefaultBlendState;
 		mutable RasterizerStatePtr mDefaultRasterizerState;
 		mutable RasterizerStatePtr mDefaultRasterizerState;
@@ -89,7 +210,7 @@ namespace BansheeEngine
 	/**
 	/**
 	 * @brief	Handles creation of various render states.
 	 * @brief	Handles creation of various render states.
 	 */
 	 */
-	class BS_CORE_EXPORT RenderStateCoreManager : public Module<RenderStateCoreManager>
+	class BS_CORE_EXPORT RenderStateCoreManager : public Module<RenderStateCoreManager>, TRenderStateManager<true>
 	{
 	{
 	public:
 	public:
 		/**
 		/**
@@ -143,6 +264,10 @@ namespace BansheeEngine
 		friend class BlendState;
 		friend class BlendState;
 		friend class RasterizerState;
 		friend class RasterizerState;
 		friend class DepthStencilState;
 		friend class DepthStencilState;
+		friend class SamplerStateCore;
+		friend class BlendStateCore;
+		friend class RasterizerStateCore;
+		friend class DepthStencilStateCore;
 
 
 		/**
 		/**
 		 * @copydoc	createSamplerState
 		 * @copydoc	createSamplerState
@@ -163,5 +288,6 @@ namespace BansheeEngine
 		 * @copydoc	createDepthStencilState
 		 * @copydoc	createDepthStencilState
 		 */
 		 */
 		virtual SPtr<DepthStencilStateCore> createDepthStencilStateInternal(const DEPTH_STENCIL_STATE_DESC& desc) const;
 		virtual SPtr<DepthStencilStateCore> createDepthStencilStateInternal(const DEPTH_STENCIL_STATE_DESC& desc) const;
+
 	};
 	};
 }
 }

+ 31 - 5
BansheeCore/Include/BsSamplerState.h

@@ -23,6 +23,8 @@ namespace BansheeEngine
 			mipMax(FLT_MAX), borderColor(Color::White)
 			mipMax(FLT_MAX), borderColor(Color::White)
 		{ }
 		{ }
 
 
+		bool operator==(const SAMPLER_STATE_DESC& rhs) const;
+
 		UVWAddressingMode addressMode;
 		UVWAddressingMode addressMode;
 		FilterOptions minFilter;
 		FilterOptions minFilter;
 		FilterOptions magFilter;
 		FilterOptions magFilter;
@@ -88,11 +90,18 @@ namespace BansheeEngine
 		 */
 		 */
 		const Color& getBorderColor() const;
 		const Color& getBorderColor() const;
 
 
+		/**
+		 * @brief	Returns the hash value generated from the sampler state properties.
+		 */
+		UINT64 getHash() const { return mHash; }
+
 	protected:
 	protected:
 		friend class SamplerState;
 		friend class SamplerState;
+		friend class SamplerStateCore;
 		friend class SamplerStateRTTI;
 		friend class SamplerStateRTTI;
 
 
 		SAMPLER_STATE_DESC mData;
 		SAMPLER_STATE_DESC mData;
+		UINT64 mHash;
 	};
 	};
 
 
 	/**
 	/**
@@ -105,7 +114,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT SamplerStateCore : public CoreObjectCore
 	class BS_CORE_EXPORT SamplerStateCore : public CoreObjectCore
 	{
 	{
 	public:
 	public:
-		virtual ~SamplerStateCore() {}
+		virtual ~SamplerStateCore();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the sampler state.
 		 * @brief	Returns information about the sampler state.
@@ -136,7 +145,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT SamplerState : public IReflectable, public CoreObject
 	class BS_CORE_EXPORT SamplerState : public IReflectable, public CoreObject
     {
     {
     public:
     public:
-		virtual ~SamplerState() {}
+		virtual ~SamplerState();
 
 
 		/**
 		/**
 		 * @brief	Returns information about the sampler state.
 		 * @brief	Returns information about the sampler state.
@@ -159,13 +168,18 @@ namespace BansheeEngine
 		 */
 		 */
 		static const SamplerStatePtr& getDefault();
 		static const SamplerStatePtr& getDefault();
 
 
+		/**
+		 * @brief	Generates a hash value from a sampler state descriptor.
+		 */
+		static UINT64 generateHash(const SAMPLER_STATE_DESC& desc);
+
 	protected:
 	protected:
 		SamplerState(const SAMPLER_STATE_DESC& desc);
 		SamplerState(const SAMPLER_STATE_DESC& desc);
 
 
 		/**
 		/**
 		 * @copydoc	CoreObjectCore::createCore
 		 * @copydoc	CoreObjectCore::createCore
 		 */
 		 */
-		SPtr<CoreObjectCore> createCore() const;
+		SPtr<CoreObjectCore> createCore() const override;
 
 
 		SamplerProperties mProperties;
 		SamplerProperties mProperties;
 
 
@@ -178,6 +192,18 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class SamplerStateRTTI;
 		friend class SamplerStateRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;	
+		virtual RTTITypeBase* getRTTI() const override;
     };
     };
-}
+}
+
+/**
+ * @brief	Hash value generator for SAMPLER_STATE_DESC.
+ */
+template<>
+struct std::hash<BansheeEngine::SAMPLER_STATE_DESC>
+{
+	size_t operator()(const BansheeEngine::SAMPLER_STATE_DESC& value) const
+	{
+		return (size_t)BansheeEngine::SamplerState::generateHash(value);
+	}
+};

+ 5 - 5
BansheeCore/Include/BsSamplerStateRTTI.h

@@ -21,26 +21,26 @@ namespace BansheeEngine
 			addPlainField("mData", 0, &SamplerStateRTTI::getData, &SamplerStateRTTI::setData);
 			addPlainField("mData", 0, &SamplerStateRTTI::getData, &SamplerStateRTTI::setData);
 		}
 		}
 
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj) override
 		{
 		{
 			SamplerState* samplerState = static_cast<SamplerState*>(obj);
 			SamplerState* samplerState = static_cast<SamplerState*>(obj);
 			samplerState->initialize();
 			samplerState->initialize();
 		}
 		}
 
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "SamplerState";
 			static String name = "SamplerState";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_SamplerState;
 			return TID_SamplerState;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
-			return RenderStateManager::instance().createEmptySamplerState();
+			return RenderStateManager::instance()._createSamplerStatePtr(SAMPLER_STATE_DESC());
 		}
 		}
 	};
 	};
 }
 }

+ 60 - 1
BansheeCore/Source/BsBlendState.cpp

@@ -6,8 +6,36 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	bool RENDER_TARGET_BLEND_STATE_DESC::operator == (const RENDER_TARGET_BLEND_STATE_DESC& rhs) const
+	{
+		return blendEnable == rhs.blendEnable &&
+			srcBlend == rhs.srcBlend &&
+			dstBlend == rhs.dstBlend &&
+			blendOp == rhs.blendOp &&
+			srcBlendAlpha == rhs.srcBlendAlpha &&
+			dstBlendAlpha == rhs.dstBlendAlpha &&
+			blendOpAlpha == rhs.blendOpAlpha &&
+			renderTargetWriteMask == rhs.renderTargetWriteMask;
+	}
+
+	bool BLEND_STATE_DESC::operator == (const BLEND_STATE_DESC& rhs) const
+	{
+		bool equals = alphaToCoverageEnable == rhs.alphaToCoverageEnable &&
+			independantBlendEnable == rhs.independantBlendEnable;
+
+		if (equals)
+		{
+			for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+			{
+				equals |= renderTargetDesc[i] == rhs.renderTargetDesc[i];
+			}
+		}
+
+		return equals;
+	}
+
 	BlendProperties::BlendProperties(const BLEND_STATE_DESC& desc)
 	BlendProperties::BlendProperties(const BLEND_STATE_DESC& desc)
-		:mData(desc)
+		:mData(desc), mHash(BlendState::generateHash(desc))
 	{ }
 	{ }
 
 
 	bool BlendProperties::getBlendEnabled(UINT32 renderTargetIdx) const
 	bool BlendProperties::getBlendEnabled(UINT32 renderTargetIdx) const
@@ -72,6 +100,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	BlendStateCore::~BlendStateCore()
+	{
+		RenderStateCoreManager::instance().notifyBlendStateDestroyed(mProperties.mData);
+	}
+
 	const BlendProperties& BlendStateCore::getProperties() const
 	const BlendProperties& BlendStateCore::getProperties() const
 	{
 	{
 		return mProperties;
 		return mProperties;
@@ -86,6 +119,11 @@ namespace BansheeEngine
 		:mProperties(desc)
 		:mProperties(desc)
 	{ }
 	{ }
 
 
+	BlendState::~BlendState()
+	{
+		RenderStateManager::instance().notifyBlendStateDestroyed(mProperties.mData);
+	}
+
 	SPtr<BlendStateCore> BlendState::getCore() const
 	SPtr<BlendStateCore> BlendState::getCore() const
 	{
 	{
 		return std::static_pointer_cast<BlendStateCore>(mCoreSpecific);
 		return std::static_pointer_cast<BlendStateCore>(mCoreSpecific);
@@ -111,6 +149,27 @@ namespace BansheeEngine
 		return RenderStateManager::instance().createBlendState(desc);
 		return RenderStateManager::instance().createBlendState(desc);
 	}
 	}
 
 
+	UINT64 BlendState::generateHash(const BLEND_STATE_DESC& desc)
+	{
+		size_t hash = 0;
+		hash_combine(hash, desc.alphaToCoverageEnable);
+		hash_combine(hash, desc.independantBlendEnable);
+
+		for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+		{
+			hash_combine(hash, desc.renderTargetDesc[i].blendEnable);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlend);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlend);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOp);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlendAlpha);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlendAlpha);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOpAlpha);
+			hash_combine(hash, desc.renderTargetDesc[i].renderTargetWriteMask);
+		}
+
+		return (UINT64)hash;
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								RTTI		                     		*/
 	/* 								RTTI		                     		*/
 	/************************************************************************/
 	/************************************************************************/

+ 47 - 40
BansheeCore/Source/BsCoreRenderer.cpp

@@ -7,9 +7,13 @@
 #include "BsBlendState.h"
 #include "BsBlendState.h"
 #include "BsDepthStencilState.h"
 #include "BsDepthStencilState.h"
 #include "BsRasterizerState.h"
 #include "BsRasterizerState.h"
+#include "BsGpuParams.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	CoreRenderer::CoreRenderer()
+	{ }
+
 	RendererMeshDataPtr CoreRenderer::_createMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType)
 	RendererMeshDataPtr CoreRenderer::_createMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType)
 	{
 	{
 		return bs_shared_ptr<RendererMeshData, PoolAlloc>(new (bs_alloc<RendererMeshData, PoolAlloc>()) 
 		return bs_shared_ptr<RendererMeshData, PoolAlloc>(new (bs_alloc<RendererMeshData, PoolAlloc>()) 
@@ -48,53 +52,56 @@ namespace BansheeEngine
 		SPtr<PassCore> pass = material->getPass(passIdx);
 		SPtr<PassCore> pass = material->getPass(passIdx);
 		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
 		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
 
 
-		if (pass->hasVertexProgram())
+		struct StageData
 		{
 		{
-			rs.bindGpuProgram(pass->getVertexProgram());
-			rs.bindGpuParams(GPT_VERTEX_PROGRAM, passParams->mVertParams);
-		}
-		else
-			rs.unbindGpuProgram(GPT_VERTEX_PROGRAM);
-
-		if (pass->hasFragmentProgram())
+			GpuProgramType type;
+			bool enable;
+			SPtr<GpuParamsCore> params;
+			SPtr<GpuProgramCore> program;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
 		{
 		{
-			rs.bindGpuProgram(pass->getFragmentProgram());
-			rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, passParams->mFragParams);
-		}
-		else
-			rs.unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
-
-		if (pass->hasGeometryProgram())
-		{
-			rs.bindGpuProgram(pass->getGeometryProgram());
-			rs.bindGpuParams(GPT_GEOMETRY_PROGRAM, passParams->mGeomParams);
-		}
-		else
-			rs.unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
+			{
+				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()
+			}
+		};
 
 
-		if (pass->hasHullProgram())
+		for (UINT32 i = 0; i < numStages; i++)
 		{
 		{
-			rs.bindGpuProgram(pass->getHullProgram());
-			rs.bindGpuParams(GPT_HULL_PROGRAM, passParams->mHullParams);
-		}
-		else
-			rs.unbindGpuProgram(GPT_HULL_PROGRAM);
+			const StageData& stage = stages[i];
 
 
-		if (pass->hasDomainProgram())
-		{
-			rs.bindGpuProgram(pass->getDomainProgram());
-			rs.bindGpuParams(GPT_DOMAIN_PROGRAM, passParams->mDomainParams);
-		}
-		else
-			rs.unbindGpuProgram(GPT_DOMAIN_PROGRAM);
+			if (stage.enable)
+			{
+				rs.bindGpuProgram(stage.program);
+				rs.setGpuParams(stage.type, stage.params);
 
 
-		if (pass->hasComputeProgram())
-		{
-			rs.bindGpuProgram(pass->getComputeProgram());
-			rs.bindGpuParams(GPT_COMPUTE_PROGRAM, passParams->mComputeParams);
+			}
+			else
+				rs.unbindGpuProgram(stage.type);
 		}
 		}
-		else
-			rs.unbindGpuProgram(GPT_COMPUTE_PROGRAM);
 
 
 		// TODO - Try to limit amount of state changes, if previous state is already the same
 		// TODO - Try to limit amount of state changes, if previous state is already the same
 
 

+ 50 - 1
BansheeCore/Source/BsDepthStencilState.cpp

@@ -7,8 +7,26 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	bool DEPTH_STENCIL_STATE_DESC::operator == (const DEPTH_STENCIL_STATE_DESC& rhs) const
+	{
+		return depthReadEnable == rhs.depthReadEnable &&
+			depthWriteEnable == rhs.depthWriteEnable &&
+			depthComparisonFunc == rhs.depthComparisonFunc &&
+			stencilEnable == rhs.stencilEnable &&
+			stencilReadMask == rhs.stencilReadMask &&
+			stencilWriteMask == rhs.stencilWriteMask &&
+			frontStencilFailOp == rhs.frontStencilFailOp &&
+			frontStencilZFailOp == rhs.frontStencilZFailOp &&
+			frontStencilPassOp == rhs.frontStencilPassOp &&
+			frontStencilComparisonFunc == rhs.frontStencilComparisonFunc &&
+			backStencilFailOp == rhs.backStencilFailOp &&
+			backStencilZFailOp == rhs.backStencilZFailOp &&
+			backStencilPassOp == rhs.backStencilPassOp &&
+			backStencilComparisonFunc == rhs.backStencilComparisonFunc;
+	}
+
 	DepthStencilProperties::DepthStencilProperties(const DEPTH_STENCIL_STATE_DESC& desc)
 	DepthStencilProperties::DepthStencilProperties(const DEPTH_STENCIL_STATE_DESC& desc)
-		:mData(desc)
+		:mData(desc), mHash(DepthStencilState::generateHash(desc))
 	{
 	{
 
 
 	}
 	}
@@ -19,6 +37,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	DepthStencilStateCore::~DepthStencilStateCore()
+	{
+		RenderStateCoreManager::instance().notifyDepthStencilStateDestroyed(mProperties.mData);
+	}
+
 	const DepthStencilProperties& DepthStencilStateCore::getProperties() const
 	const DepthStencilProperties& DepthStencilStateCore::getProperties() const
 	{
 	{
 		return mProperties;
 		return mProperties;
@@ -35,6 +58,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	DepthStencilState::~DepthStencilState()
+	{
+		RenderStateManager::instance().notifyDepthStencilStateDestroyed(mProperties.mData);
+	}
+
 	SPtr<DepthStencilStateCore> DepthStencilState::getCore() const
 	SPtr<DepthStencilStateCore> DepthStencilState::getCore() const
 	{
 	{
 		return std::static_pointer_cast<DepthStencilStateCore>(mCoreSpecific);
 		return std::static_pointer_cast<DepthStencilStateCore>(mCoreSpecific);
@@ -60,6 +88,27 @@ namespace BansheeEngine
 		return RenderStateManager::instance().createDepthStencilState(desc);
 		return RenderStateManager::instance().createDepthStencilState(desc);
 	}
 	}
 
 
+	UINT64 DepthStencilState::generateHash(const DEPTH_STENCIL_STATE_DESC& desc)
+	{
+		size_t hash = 0;
+		hash_combine(hash, desc.depthReadEnable);
+		hash_combine(hash, desc.depthWriteEnable);
+		hash_combine(hash, (UINT32)desc.depthComparisonFunc);
+		hash_combine(hash, desc.stencilEnable);
+		hash_combine(hash, desc.stencilReadMask);
+		hash_combine(hash, desc.stencilWriteMask);
+		hash_combine(hash, (UINT32)desc.frontStencilFailOp);
+		hash_combine(hash, (UINT32)desc.frontStencilZFailOp);
+		hash_combine(hash, (UINT32)desc.frontStencilPassOp);
+		hash_combine(hash, (UINT32)desc.frontStencilComparisonFunc);
+		hash_combine(hash, (UINT32)desc.backStencilFailOp);
+		hash_combine(hash, (UINT32)desc.backStencilZFailOp);
+		hash_combine(hash, (UINT32)desc.backStencilPassOp);
+		hash_combine(hash, (UINT32)desc.backStencilComparisonFunc);
+
+		return (UINT64)hash;
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								RTTI		                     		*/
 	/* 								RTTI		                     		*/
 	/************************************************************************/
 	/************************************************************************/

+ 40 - 1
BansheeCore/Source/BsRasterizerState.cpp

@@ -6,8 +6,21 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	bool RASTERIZER_STATE_DESC::operator == (const RASTERIZER_STATE_DESC& rhs) const
+	{
+		return polygonMode == rhs.polygonMode &&
+			cullMode == rhs.cullMode &&
+			depthBias == rhs.depthBias &&
+			depthBiasClamp == rhs.depthBiasClamp &&
+			slopeScaledDepthBias == rhs.slopeScaledDepthBias &&
+			depthClipEnable == rhs.depthClipEnable &&
+			scissorEnable == rhs.scissorEnable &&
+			multisampleEnable == rhs.multisampleEnable &&
+			antialiasedLineEnable == rhs.antialiasedLineEnable;
+	}
+
 	RasterizerProperties::RasterizerProperties(const RASTERIZER_STATE_DESC& desc)
 	RasterizerProperties::RasterizerProperties(const RASTERIZER_STATE_DESC& desc)
-		:mData(desc)
+		:mData(desc), mHash(RasterizerState::generateHash(desc))
 	{ }
 	{ }
 
 
 	RasterizerStateCore::RasterizerStateCore(const RASTERIZER_STATE_DESC& desc)
 	RasterizerStateCore::RasterizerStateCore(const RASTERIZER_STATE_DESC& desc)
@@ -16,6 +29,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	RasterizerStateCore::~RasterizerStateCore()
+	{
+		RenderStateCoreManager::instance().notifyRasterizerStateDestroyed(mProperties.mData);
+	}
+
 	const RasterizerProperties& RasterizerStateCore::getProperties() const
 	const RasterizerProperties& RasterizerStateCore::getProperties() const
 	{
 	{
 		return mProperties;
 		return mProperties;
@@ -32,6 +50,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	RasterizerState::~RasterizerState()
+	{
+		RenderStateManager::instance().notifyRasterizerStateDestroyed(mProperties.mData);
+	}
+
 	SPtr<RasterizerStateCore> RasterizerState::getCore() const
 	SPtr<RasterizerStateCore> RasterizerState::getCore() const
 	{
 	{
 		return std::static_pointer_cast<RasterizerStateCore>(mCoreSpecific);
 		return std::static_pointer_cast<RasterizerStateCore>(mCoreSpecific);
@@ -57,6 +80,22 @@ namespace BansheeEngine
 		return RenderStateManager::instance().createRasterizerState(desc);
 		return RenderStateManager::instance().createRasterizerState(desc);
 	}
 	}
 
 
+	UINT64 RasterizerState::generateHash(const RASTERIZER_STATE_DESC& desc)
+	{
+		size_t hash = 0;
+		hash_combine(hash, (UINT32)desc.polygonMode);
+		hash_combine(hash, (UINT32)desc.cullMode);
+		hash_combine(hash, desc.depthBias);
+		hash_combine(hash, desc.depthBiasClamp);
+		hash_combine(hash, desc.slopeScaledDepthBias);
+		hash_combine(hash, desc.depthClipEnable);
+		hash_combine(hash, desc.scissorEnable);
+		hash_combine(hash, desc.multisampleEnable);
+		hash_combine(hash, desc.antialiasedLineEnable);
+
+		return (UINT64)hash;
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								RTTI		                     		*/
 	/* 								RTTI		                     		*/
 	/************************************************************************/
 	/************************************************************************/

+ 46 - 2
BansheeCore/Source/BsRenderAPI.cpp

@@ -131,9 +131,14 @@ namespace BansheeEngine
 		accessor.queueCommand(std::bind(&RenderAPICore::unbindGpuProgram, RenderAPICore::instancePtr(), gptype));
 		accessor.queueCommand(std::bind(&RenderAPICore::unbindGpuProgram, RenderAPICore::instancePtr(), gptype));
 	}
 	}
 
 
-	void RenderAPI::bindGpuParams(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params)
+	void RenderAPI::setConstantBuffers(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params)
 	{
 	{
-		accessor.queueCommand(std::bind(&RenderAPICore::bindGpuParams, RenderAPICore::instancePtr(), gptype, params->getCore()));
+		accessor.queueCommand(std::bind(&RenderAPICore::setConstantBuffers, RenderAPICore::instancePtr(), gptype, params->getCore()));
+	}
+
+	void RenderAPI::setGpuParams(CoreAccessor& accessor, GpuProgramType gptype, const GpuParamsPtr& params)
+	{
+		accessor.queueCommand(std::bind(&RenderAPICore::setGpuParams, RenderAPICore::instancePtr(), gptype, params->getCore()));
 	}
 	}
 
 
 	void RenderAPI::beginRender(CoreAccessor& accessor)
 	void RenderAPI::beginRender(CoreAccessor& accessor)
@@ -405,6 +410,45 @@ namespace BansheeEngine
         return false;
         return false;
 	}
 	}
 
 
+	void RenderAPICore::setGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params)
+	{
+		const GpuParamDesc& paramDesc = params->getParamDesc();
+
+		for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
+		{
+			SPtr<SamplerStateCore> samplerState = params->getSamplerState(iter->second.slot);
+
+			if (samplerState == nullptr)
+				setSamplerState(gptype, iter->second.slot, SamplerStateCore::getDefault());
+			else
+				setSamplerState(gptype, 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)
+					setTexture(gptype, iter->second.slot, false, nullptr);
+				else
+					setTexture(gptype, iter->second.slot, true, texture);
+			}
+			else
+			{
+				const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+				if (texture == nullptr)
+					setLoadStoreTexture(gptype, iter->second.slot, false, nullptr, surface);
+				else
+					setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
+			}
+		}
+
+		setConstantBuffers(gptype, params);
+	}
+
 	void RenderAPICore::swapBuffers(const SPtr<RenderTargetCore>& target)
 	void RenderAPICore::swapBuffers(const SPtr<RenderTargetCore>& target)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;

+ 199 - 36
BansheeCore/Source/BsRenderStateManager.cpp

@@ -6,73 +6,212 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	template<bool Core>
+	void TRenderStateManager<Core>::notifySamplerStateCreated(const SAMPLER_STATE_DESC& desc, const SPtr<SamplerStateType>& state) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedSamplerStates[desc] = state;
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyBlendStateCreated(const BLEND_STATE_DESC& desc, const SPtr<BlendStateType>& state) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedBlendStates[desc] = state;
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyRasterizerStateCreated(const RASTERIZER_STATE_DESC& desc, const SPtr<RasterizerStateType>& state) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedRasterizerStates[desc] = state;
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyDepthStencilStateCreated(const DEPTH_STENCIL_STATE_DESC& desc, const SPtr<DepthStencilStateType>& state) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedDepthStencilStates[desc] = state;
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifySamplerStateDestroyed(const SAMPLER_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedSamplerStates.erase(desc);
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyBlendStateDestroyed(const BLEND_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedBlendStates.erase(desc);
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyRasterizerStateDestroyed(const RASTERIZER_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedRasterizerStates.erase(desc);
+	}
+
+	template<bool Core>
+	void TRenderStateManager<Core>::notifyDepthStencilStateDestroyed(const DEPTH_STENCIL_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		mCachedDepthStencilStates.erase(desc);
+	}
+
+	template<bool Core>
+	SPtr<typename TRenderStateManager<Core>::SamplerStateType> TRenderStateManager<Core>::findCachedState(const SAMPLER_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		auto iterFind = mCachedSamplerStates.find(desc);
+		if (iterFind != mCachedSamplerStates.end())
+			return iterFind->second.lock();
+
+		return nullptr;
+	}
+
+	template<bool Core>
+	SPtr<typename TRenderStateManager<Core>::BlendStateType> TRenderStateManager<Core>::findCachedState(const BLEND_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		auto iterFind = mCachedBlendStates.find(desc);
+		if (iterFind != mCachedBlendStates.end())
+			return iterFind->second.lock();
+
+		return nullptr;
+	}
+
+	template<bool Core>
+	SPtr<typename TRenderStateManager<Core>::RasterizerStateType> TRenderStateManager<Core>::findCachedState(const RASTERIZER_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		auto iterFind = mCachedRasterizerStates.find(desc);
+		if (iterFind != mCachedRasterizerStates.end())
+			return iterFind->second.lock();
+
+		return nullptr;
+	}
+
+	template<bool Core>
+	SPtr<typename TRenderStateManager<Core>::DepthStencilStateType> TRenderStateManager<Core>::findCachedState(const DEPTH_STENCIL_STATE_DESC& desc) const
+	{
+		BS_LOCK_MUTEX(mMutex);
+
+		auto iterFind = mCachedDepthStencilStates.find(desc);
+		if (iterFind != mCachedDepthStencilStates.end())
+			return iterFind->second.lock();
+
+		return nullptr;
+	}
+
+	template class TRenderStateManager < true > ;
+	template class TRenderStateManager < false >;
+
 	SamplerStatePtr RenderStateManager::createSamplerState(const SAMPLER_STATE_DESC& desc) const
 	SamplerStatePtr RenderStateManager::createSamplerState(const SAMPLER_STATE_DESC& desc) const
 	{
 	{
-		SamplerStatePtr samplerState = bs_core_ptr<SamplerState, GenAlloc>(new (bs_alloc<SamplerState>()) SamplerState(desc));
-		samplerState->_setThisPtr(samplerState);
-		samplerState->initialize();
+		SPtr<SamplerState> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_core_ptr<SamplerState, GenAlloc>(new (bs_alloc<SamplerState>()) SamplerState(desc));
+			state->_setThisPtr(state);
+			state->initialize();
 
 
-		return samplerState;
+			notifySamplerStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	DepthStencilStatePtr RenderStateManager::createDepthStencilState(const DEPTH_STENCIL_STATE_DESC& desc) const
 	DepthStencilStatePtr RenderStateManager::createDepthStencilState(const DEPTH_STENCIL_STATE_DESC& desc) const
 	{
 	{
-		DepthStencilStatePtr depthStencilState = bs_core_ptr<DepthStencilState, GenAlloc>(new (bs_alloc<DepthStencilState>()) DepthStencilState(desc));
-		depthStencilState->_setThisPtr(depthStencilState);
-		depthStencilState->initialize();
+		SPtr<DepthStencilState> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_core_ptr<DepthStencilState, GenAlloc>(new (bs_alloc<DepthStencilState>()) DepthStencilState(desc));
+			state->_setThisPtr(state);
+			state->initialize();
 
 
-		return depthStencilState;
+			notifyDepthStencilStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	RasterizerStatePtr RenderStateManager::createRasterizerState(const RASTERIZER_STATE_DESC& desc) const
 	RasterizerStatePtr RenderStateManager::createRasterizerState(const RASTERIZER_STATE_DESC& desc) const
 	{
 	{
-		RasterizerStatePtr rasterizerState = bs_core_ptr<RasterizerState, GenAlloc>(new (bs_alloc<RasterizerState>()) RasterizerState(desc));
-		rasterizerState->_setThisPtr(rasterizerState);
-		rasterizerState->initialize();
+		SPtr<RasterizerState> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_core_ptr<RasterizerState, GenAlloc>(new (bs_alloc<RasterizerState>()) RasterizerState(desc));
+			state->_setThisPtr(state);
+			state->initialize();
 
 
-		return rasterizerState;
+			notifyRasterizerStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	BlendStatePtr RenderStateManager::createBlendState(const BLEND_STATE_DESC& desc) const
 	BlendStatePtr RenderStateManager::createBlendState(const BLEND_STATE_DESC& desc) const
 	{
 	{
-		BlendStatePtr blendState = bs_core_ptr<BlendState, GenAlloc>(new (bs_alloc<BlendState>()) BlendState(desc));
-		blendState->_setThisPtr(blendState);
-		blendState->initialize();
+		SPtr<BlendState> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_core_ptr<BlendState, GenAlloc>(new (bs_alloc<BlendState>()) BlendState(desc));
+			state->_setThisPtr(state);
+			state->initialize();
 
 
-		return blendState;
+			notifyBlendStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
-	SamplerStatePtr RenderStateManager::createEmptySamplerState() const
+	SamplerStatePtr RenderStateManager::_createSamplerStatePtr(const SAMPLER_STATE_DESC& desc) const
 	{
 	{
 		SamplerStatePtr samplerState = bs_core_ptr<SamplerState, GenAlloc>(
 		SamplerStatePtr samplerState = bs_core_ptr<SamplerState, GenAlloc>(
-			new (bs_alloc<SamplerState>()) SamplerState(SAMPLER_STATE_DESC()));
+			new (bs_alloc<SamplerState>()) SamplerState(desc));
 		samplerState->_setThisPtr(samplerState);
 		samplerState->_setThisPtr(samplerState);
 
 
 		return samplerState;
 		return samplerState;
 	}
 	}
 
 
-	DepthStencilStatePtr RenderStateManager::createEmptyDepthStencilState() const
+	DepthStencilStatePtr RenderStateManager::_createDepthStencilStatePtr(const DEPTH_STENCIL_STATE_DESC& desc) const
 	{
 	{
 		DepthStencilStatePtr depthStencilState = bs_core_ptr<DepthStencilState, GenAlloc>(
 		DepthStencilStatePtr depthStencilState = bs_core_ptr<DepthStencilState, GenAlloc>(
-			new (bs_alloc<DepthStencilState>()) DepthStencilState(DEPTH_STENCIL_STATE_DESC()));
+			new (bs_alloc<DepthStencilState>()) DepthStencilState(desc));
 		depthStencilState->_setThisPtr(depthStencilState);
 		depthStencilState->_setThisPtr(depthStencilState);
 
 
 		return depthStencilState;
 		return depthStencilState;
 	}
 	}
 
 
-	RasterizerStatePtr RenderStateManager::createEmptyRasterizerState() const
+	RasterizerStatePtr RenderStateManager::_createRasterizerStatePtr(const RASTERIZER_STATE_DESC& desc) const
 	{
 	{
 		RasterizerStatePtr rasterizerState = bs_core_ptr<RasterizerState, GenAlloc>(
 		RasterizerStatePtr rasterizerState = bs_core_ptr<RasterizerState, GenAlloc>(
-			new (bs_alloc<RasterizerState>()) RasterizerState(RASTERIZER_STATE_DESC()));
+			new (bs_alloc<RasterizerState>()) RasterizerState(desc));
 		rasterizerState->_setThisPtr(rasterizerState);
 		rasterizerState->_setThisPtr(rasterizerState);
 
 
 		return rasterizerState;
 		return rasterizerState;
 	}
 	}
 
 
-	BlendStatePtr RenderStateManager::createEmptyBlendState() const
+	BlendStatePtr RenderStateManager::_createBlendStatePtr(const BLEND_STATE_DESC& desc) const
 	{
 	{
 		BlendStatePtr blendState = bs_core_ptr<BlendState, GenAlloc>(
 		BlendStatePtr blendState = bs_core_ptr<BlendState, GenAlloc>(
-			new (bs_alloc<BlendState>()) BlendState(BLEND_STATE_DESC()));
+			new (bs_alloc<BlendState>()) BlendState(desc));
 		blendState->_setThisPtr(blendState);
 		blendState->_setThisPtr(blendState);
 
 
 		return blendState;
 		return blendState;
@@ -176,33 +315,57 @@ namespace BansheeEngine
 
 
 	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const
 	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const
 	{
 	{
-		SPtr<SamplerStateCore> samplerState = bs_shared_ptr<SamplerStateCore, GenAlloc>(new (bs_alloc<SamplerStateCore>()) SamplerStateCore(desc));
-		samplerState->_setThisPtr(samplerState);
+		SPtr<SamplerStateCore> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_shared_ptr<SamplerStateCore, GenAlloc>(new (bs_alloc<SamplerStateCore>()) SamplerStateCore(desc));
+			state->_setThisPtr(state);
 
 
-		return samplerState;
+			notifySamplerStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	SPtr<DepthStencilStateCore> RenderStateCoreManager::createDepthStencilStateInternal(const DEPTH_STENCIL_STATE_DESC& desc) const
 	SPtr<DepthStencilStateCore> RenderStateCoreManager::createDepthStencilStateInternal(const DEPTH_STENCIL_STATE_DESC& desc) const
 	{
 	{
-		SPtr<DepthStencilStateCore> depthStencilState = bs_shared_ptr<DepthStencilStateCore, GenAlloc>(new (bs_alloc<DepthStencilStateCore>()) DepthStencilStateCore(desc));
-		depthStencilState->_setThisPtr(depthStencilState);
+		SPtr<DepthStencilStateCore> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			SPtr<DepthStencilStateCore> state = bs_shared_ptr<DepthStencilStateCore, GenAlloc>(new (bs_alloc<DepthStencilStateCore>()) DepthStencilStateCore(desc));
+			state->_setThisPtr(state);
 
 
-		return depthStencilState;
+			notifyDepthStencilStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	SPtr<RasterizerStateCore> RenderStateCoreManager::createRasterizerStateInternal(const RASTERIZER_STATE_DESC& desc) const
 	SPtr<RasterizerStateCore> RenderStateCoreManager::createRasterizerStateInternal(const RASTERIZER_STATE_DESC& desc) const
 	{
 	{
-		SPtr<RasterizerStateCore> rasterizerState = bs_shared_ptr<RasterizerStateCore, GenAlloc>(new (bs_alloc<RasterizerStateCore>()) RasterizerStateCore(desc));
-		rasterizerState->_setThisPtr(rasterizerState);
+		SPtr<RasterizerStateCore> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			SPtr<RasterizerStateCore> state = bs_shared_ptr<RasterizerStateCore, GenAlloc>(new (bs_alloc<RasterizerStateCore>()) RasterizerStateCore(desc));
+			state->_setThisPtr(state);
 
 
-		return rasterizerState;
+			notifyRasterizerStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 
 
 	SPtr<BlendStateCore> RenderStateCoreManager::createBlendStateInternal(const BLEND_STATE_DESC& desc) const
 	SPtr<BlendStateCore> RenderStateCoreManager::createBlendStateInternal(const BLEND_STATE_DESC& desc) const
 	{
 	{
-		SPtr<BlendStateCore> blendState = bs_shared_ptr<BlendStateCore, GenAlloc>(new (bs_alloc<BlendStateCore>()) BlendStateCore(desc));
-		blendState->_setThisPtr(blendState);
+		SPtr<BlendStateCore> state = findCachedState(desc);
+		if (state == nullptr)
+		{
+			state = bs_shared_ptr<BlendStateCore, GenAlloc>(new (bs_alloc<BlendStateCore>()) BlendStateCore(desc));
+			state->_setThisPtr(state);
 
 
-		return blendState;
+			notifyBlendStateCreated(desc, state);
+		}
+
+		return state;
 	}
 	}
 }
 }

+ 44 - 1
BansheeCore/Source/BsSamplerState.cpp

@@ -7,8 +7,22 @@
 
 
 namespace BansheeEngine 
 namespace BansheeEngine 
 {
 {
+	bool SAMPLER_STATE_DESC::operator == (const SAMPLER_STATE_DESC& rhs) const
+	{
+		return addressMode == rhs.addressMode && 
+			minFilter == rhs.minFilter && 
+			magFilter == rhs.magFilter && 
+			mipFilter == rhs.mipFilter &&
+			maxAniso == rhs.maxAniso && 
+			mipmapBias == rhs.mipmapBias && 
+			mipMin == rhs.mipMin && 
+			mipMax == rhs.mipMax && 
+			borderColor == rhs.borderColor && 
+			comparisonFunc == rhs.comparisonFunc;
+	}
+
 	SamplerProperties::SamplerProperties(const SAMPLER_STATE_DESC& desc)
 	SamplerProperties::SamplerProperties(const SAMPLER_STATE_DESC& desc)
-		:mData(desc)
+		:mData(desc), mHash(SamplerState::generateHash(desc))
 	{ }
 	{ }
 
 
 	FilterOptions SamplerProperties::getTextureFiltering(FilterType ft) const
 	FilterOptions SamplerProperties::getTextureFiltering(FilterType ft) const
@@ -34,7 +48,12 @@ namespace BansheeEngine
 	SamplerStateCore::SamplerStateCore(const SAMPLER_STATE_DESC& desc)
 	SamplerStateCore::SamplerStateCore(const SAMPLER_STATE_DESC& desc)
 		:mProperties(desc)
 		:mProperties(desc)
 	{
 	{
+		
+	}
 
 
+	SamplerStateCore::~SamplerStateCore()
+	{
+		RenderStateCoreManager::instance().notifySamplerStateDestroyed(mProperties.mData);
 	}
 	}
 
 
 	const SamplerProperties& SamplerStateCore::getProperties() const
 	const SamplerProperties& SamplerStateCore::getProperties() const
@@ -53,6 +72,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	SamplerState::~SamplerState()
+	{
+		RenderStateManager::instance().notifySamplerStateDestroyed(mProperties.mData);
+	}
+
 	SPtr<SamplerStateCore> SamplerState::getCore() const
 	SPtr<SamplerStateCore> SamplerState::getCore() const
 	{
 	{
 		return std::static_pointer_cast<SamplerStateCore>(mCoreSpecific);
 		return std::static_pointer_cast<SamplerStateCore>(mCoreSpecific);
@@ -73,6 +97,25 @@ namespace BansheeEngine
 		return RenderStateManager::instance().getDefaultSamplerState();
 		return RenderStateManager::instance().getDefaultSamplerState();
 	}
 	}
 
 
+	UINT64 SamplerState::generateHash(const SAMPLER_STATE_DESC& desc)
+	{
+		size_t hash = 0;
+		hash_combine(hash, (UINT32)desc.addressMode.u);
+		hash_combine(hash, (UINT32)desc.addressMode.v);
+		hash_combine(hash, (UINT32)desc.addressMode.w);
+		hash_combine(hash, (UINT32)desc.minFilter);
+		hash_combine(hash, (UINT32)desc.magFilter);
+		hash_combine(hash, (UINT32)desc.mipFilter);
+		hash_combine(hash, desc.maxAniso);
+		hash_combine(hash, desc.mipmapBias);
+		hash_combine(hash, desc.mipMin);
+		hash_combine(hash, desc.mipMax);
+		hash_combine(hash, desc.borderColor);
+		hash_combine(hash, (UINT32)desc.comparisonFunc);
+
+		return (UINT64)hash;
+	}
+
 	const SamplerProperties& SamplerState::getProperties() const
 	const SamplerProperties& SamplerState::getProperties() const
 	{
 	{
 		return mProperties;
 		return mProperties;

+ 2 - 2
BansheeD3D11RenderSystem/Include/BsD3D11RenderAPI.h

@@ -137,9 +137,9 @@ namespace BansheeEngine
 		void unbindGpuProgram(GpuProgramType gptype);
 		void unbindGpuProgram(GpuProgramType gptype);
 
 
 		/** 
 		/** 
-		 * @copydoc RenderAPICore::bindGpuParams
+		 * @copydoc RenderAPICore::setConstantBuffers
 		 */
 		 */
-		void bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
+		void setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
 		
 		
 		/**
 		/**
 		 * @copydoc	RenderAPICore::setClipPlanesImpl
 		 * @copydoc	RenderAPICore::setClipPlanesImpl

+ 2 - 37
BansheeD3D11RenderSystem/Source/BsD3D11RenderAPI.cpp

@@ -553,50 +553,15 @@ namespace BansheeEngine
 		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 	}
 	}
 
 
-	void D3D11RenderAPI::bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
+	void D3D11RenderAPI::setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
 		bindableParams->updateHardwareBuffers();
 		bindableParams->updateHardwareBuffers();
-
 		const GpuParamDesc& paramDesc = bindableParams->getParamDesc();
 		const GpuParamDesc& paramDesc = bindableParams->getParamDesc();
-		
-		for(auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-		{
-			SPtr<SamplerStateCore> samplerState = bindableParams->getSamplerState(iter->second.slot);
-
-			if(samplerState == nullptr)
-				setSamplerState(gptype, iter->second.slot, SamplerStateCore::getDefault());
-			else
-				setSamplerState(gptype, iter->second.slot, samplerState);
-		}
-
-		for(auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
-		{
-			SPtr<TextureCore> texture = bindableParams->getTexture(iter->second.slot);
-
-			if (!bindableParams->isLoadStoreTexture(iter->second.slot))
-			{
-				if (texture == nullptr)
-					setTexture(gptype, iter->second.slot, false, nullptr);
-				else
-					setTexture(gptype, iter->second.slot, true, texture);
-			}
-			else
-			{
-				const TextureSurface& surface = bindableParams->getLoadStoreSurface(iter->second.slot);
-
-				if (texture == nullptr)
-					setLoadStoreTexture(gptype, iter->second.slot, false, nullptr, surface);
-				else
-					setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
-			}
-		}
 
 
 		// TODO - I assign constant buffers one by one but it might be more efficient to do them all at once?
 		// TODO - I assign constant buffers one by one but it might be more efficient to do them all at once?
-
 		ID3D11Buffer* bufferArray[1];
 		ID3D11Buffer* bufferArray[1];
-
 		for(auto iter = paramDesc.paramBlocks.begin(); iter != paramDesc.paramBlocks.end(); ++iter)
 		for(auto iter = paramDesc.paramBlocks.begin(); iter != paramDesc.paramBlocks.end(); ++iter)
 		{
 		{
 			SPtr<GpuParamBlockBufferCore> currentBlockBuffer = bindableParams->getParamBlockBuffer(iter->second.slot);
 			SPtr<GpuParamBlockBufferCore> currentBlockBuffer = bindableParams->getParamBlockBuffer(iter->second.slot);
@@ -636,7 +601,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		if (mDevice->hasError())
 		if (mDevice->hasError())
-			BS_EXCEPT(RenderingAPIException, "Failed to bindGpuParams : " + mDevice->getErrorDescription());
+			BS_EXCEPT(RenderingAPIException, "Failed to setConstantBuffers : " + mDevice->getErrorDescription());
 	}
 	}
 
 
 	void D3D11RenderAPI::draw(UINT32 vertexOffset, UINT32 vertexCount)
 	void D3D11RenderAPI::draw(UINT32 vertexOffset, UINT32 vertexCount)

+ 2 - 2
BansheeD3D9RenderSystem/Include/BsD3D9RenderAPI.h

@@ -46,9 +46,9 @@ namespace BansheeEngine
 		void unbindGpuProgram(GpuProgramType gptype);
 		void unbindGpuProgram(GpuProgramType gptype);
 
 
 		/**
 		/**
-		 * @copydoc RenderAPICore::bindGpuParams()
+		 * @copydoc RenderAPICore::setConstantBuffers()
 		 */
 		 */
-		void bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
+		void setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
 
 
 		/**
 		/**
 		 * @copydoc RenderAPICore::setVertexBuffers()
 		 * @copydoc RenderAPICore::setVertexBuffers()

+ 1 - 22
BansheeD3D9RenderSystem/Source/BsD3D9RenderAPI.cpp

@@ -267,34 +267,13 @@ namespace BansheeEngine
 		RenderAPICore::unbindGpuProgram(gptype);
 		RenderAPICore::unbindGpuProgram(gptype);
 	}
 	}
 
 
-	void D3D9RenderAPI::bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
+	void D3D9RenderAPI::setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
 		bindableParams->updateHardwareBuffers();
 		bindableParams->updateHardwareBuffers();
 		const GpuParamDesc& paramDesc = bindableParams->getParamDesc();
 		const GpuParamDesc& paramDesc = bindableParams->getParamDesc();
 
 
-		for(auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-		{
-			SPtr<SamplerStateCore> samplerState = bindableParams->getSamplerState(iter->second.slot);
-			if(samplerState == nullptr)
-				setSamplerState(gptype, iter->second.slot, SamplerStateCore::getDefault());
-			else
-				setSamplerState(gptype, iter->second.slot, samplerState);
-		}
-
-		for(auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
-		{
-			if (bindableParams->isLoadStoreTexture(iter->second.slot))
-				continue; // Not supported by DX9
-
-			SPtr<TextureCore> texture = bindableParams->getTexture(iter->second.slot);
-			if(texture == nullptr)
-				setTexture(gptype, iter->second.slot, false, nullptr);
-			else
-				setTexture(gptype, iter->second.slot, true, texture);
-		}
-
 		// Read all the buffer data so we can assign it. Not the most efficient way of accessing data
 		// Read all the buffer data so we can assign it. Not the most efficient way of accessing data
 		// but it is required in order to have standardized buffer interface.
 		// but it is required in order to have standardized buffer interface.
 		UnorderedMap<UINT32, UINT8*> bufferData;
 		UnorderedMap<UINT32, UINT8*> bufferData;

+ 2 - 2
BansheeEditor/Source/BsGizmoManager.cpp

@@ -823,7 +823,7 @@ namespace BansheeEngine
 				for (auto curRenderData : *renderData)
 				for (auto curRenderData : *renderData)
 				{
 				{
 					mIconMaterial.mTexture[passIdx].set(curRenderData.texture);
 					mIconMaterial.mTexture[passIdx].set(curRenderData.texture);
-					rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, mIconMaterial.mFragParams[passIdx]);
+					rs.setGpuParams(GPT_FRAGMENT_PROGRAM, mIconMaterial.mFragParams[passIdx]);
 
 
 					rs.drawIndexed(curIndexOffset, curRenderData.count * 6, mesh->getVertexOffset(), curRenderData.count * 4);
 					rs.drawIndexed(curIndexOffset, curRenderData.count * 6, mesh->getVertexOffset(), curRenderData.count * 4);
 					curIndexOffset += curRenderData.count * 6;
 					curIndexOffset += curRenderData.count * 6;
@@ -840,7 +840,7 @@ namespace BansheeEngine
 			for (auto curRenderData : *renderData)
 			for (auto curRenderData : *renderData)
 			{
 			{
 				mAlphaPickingMaterial.mTexture.set(curRenderData.texture);
 				mAlphaPickingMaterial.mTexture.set(curRenderData.texture);
-				rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, mAlphaPickingMaterial.mFragParams);
+				rs.setGpuParams(GPT_FRAGMENT_PROGRAM, mAlphaPickingMaterial.mFragParams);
 
 
 				rs.drawIndexed(curIndexOffset, curRenderData.count * 6, mesh->getVertexOffset(), curRenderData.count * 4);
 				rs.drawIndexed(curIndexOffset, curRenderData.count * 6, mesh->getVertexOffset(), curRenderData.count * 4);
 				curIndexOffset += curRenderData.count * 6;
 				curIndexOffset += curRenderData.count * 6;

+ 4 - 4
BansheeEditor/Source/BsScenePicking.cpp

@@ -290,16 +290,16 @@ namespace BansheeEngine
 				md.mParamPickingAlphaColor.set(color);
 				md.mParamPickingAlphaColor.set(color);
 				md.mParamPickingAlphaTexture.set(renderable.mainTexture->getCore());
 				md.mParamPickingAlphaTexture.set(renderable.mainTexture->getCore());
 
 
-				rs.bindGpuParams(GPT_VERTEX_PROGRAM, md.mParamPickingAlphaVertParams);
-				rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, md.mParamPickingAlphaFragParams);
+				rs.setGpuParams(GPT_VERTEX_PROGRAM, md.mParamPickingAlphaVertParams);
+				rs.setGpuParams(GPT_FRAGMENT_PROGRAM, md.mParamPickingAlphaFragParams);
 			}
 			}
 			else
 			else
 			{
 			{
 				md.mParamPickingWVP.set(renderable.wvpTransform);
 				md.mParamPickingWVP.set(renderable.wvpTransform);
 				md.mParamPickingColor.set(color);
 				md.mParamPickingColor.set(color);
 
 
-				rs.bindGpuParams(GPT_VERTEX_PROGRAM, md.mParamPickingVertParams);
-				rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, md.mParamPickingFragParams);
+				rs.setGpuParams(GPT_VERTEX_PROGRAM, md.mParamPickingVertParams);
+				rs.setGpuParams(GPT_FRAGMENT_PROGRAM, md.mParamPickingFragParams);
 			}
 			}
 
 
 			CoreRenderer::draw(renderable.mesh, renderable.mesh->getProperties().getSubMesh(0));
 			CoreRenderer::draw(renderable.mesh, renderable.mesh->getProperties().getSubMesh(0));

+ 8 - 1
BansheeEngine/Include/BsRenderableElement.h

@@ -41,10 +41,17 @@ namespace BansheeEngine
 		SubMesh subMesh;
 		SubMesh subMesh;
 
 
 		/**
 		/**
-		 * @brief	Proxy of the material to render the mesh with.
+		 * @brief	Material to render the mesh with.
 		 */
 		 */
 		SPtr<MaterialCore> material;
 		SPtr<MaterialCore> material;
 
 
+		/**
+		 * @brief	Optional overrides for material sampler states.
+		 *			Used when renderer wants to override certain sampling
+		 *			properties on a global scale (e.g. filtering most commonly).
+		 */
+		SPtr<SamplerStateCore>** samplerOverrides;
+
 		/**
 		/**
 		 * @brief	Custom data that may optionally be set by the RenderableHanbdler.
 		 * @brief	Custom data that may optionally be set by the RenderableHanbdler.
 		 */
 		 */

+ 2 - 2
BansheeGLRenderSystem/Include/BsGLRenderAPI.h

@@ -105,9 +105,9 @@ namespace BansheeEngine
 		void unbindGpuProgram(GpuProgramType gptype);
 		void unbindGpuProgram(GpuProgramType gptype);
 
 
 		/**
 		/**
-		 * @copydoc RenderAPICore::bindGpuParams()
+		 * @copydoc RenderAPICore::setConstantBuffers()
 		 */
 		 */
-		void bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
+		void setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& params);
 
 
 		/**
 		/**
 		 * @copydoc RenderAPICore::beginFrame()
 		 * @copydoc RenderAPICore::beginFrame()

+ 6 - 35
BansheeGLRenderSystem/Source/BsGLRenderAPI.cpp

@@ -243,7 +243,7 @@ namespace BansheeEngine
 		RenderAPICore::unbindGpuProgram(gptype);
 		RenderAPICore::unbindGpuProgram(gptype);
 	}
 	}
 
 
-	void GLRenderAPI::bindGpuParams(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
+	void GLRenderAPI::setConstantBuffers(GpuProgramType gptype, const SPtr<GpuParamsCore>& bindableParams)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
@@ -252,40 +252,6 @@ namespace BansheeEngine
 		SPtr<GLSLGpuProgramCore> activeProgram = getActiveProgram(gptype);
 		SPtr<GLSLGpuProgramCore> activeProgram = getActiveProgram(gptype);
 		GLuint glProgram = activeProgram->getGLHandle();
 		GLuint glProgram = activeProgram->getGLHandle();
 
 
-		for(auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
-		{
-			SPtr<TextureCore> texture = bindableParams->getTexture(iter->second.slot);
-
-			if (!bindableParams->isLoadStoreTexture(iter->second.slot))
-			{
-				if (texture == nullptr)
-					setTexture(gptype, iter->second.slot, false, nullptr);
-				else
-					setTexture(gptype, iter->second.slot, true, texture);
-			}
-			else
-			{
-				const TextureSurface& surface = bindableParams->getLoadStoreSurface(iter->second.slot);
-
-				if (texture == nullptr)
-					setLoadStoreTexture(gptype, iter->second.slot, false, nullptr, surface);
-				else
-					setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
-			}
-		}
-
-		for(auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-		{
-			SPtr<SamplerStateCore>& samplerState = bindableParams->getSamplerState(iter->second.slot);
-
-			if(samplerState == nullptr)
-				setSamplerState(gptype, iter->second.slot, SamplerStateCore::getDefault());
-			else
-				setSamplerState(gptype, iter->second.slot, samplerState);
-
-			glProgramUniform1i(glProgram, iter->second.slot, getGLTextureUnit(gptype, iter->second.slot));
-		}
-
 		UINT8* uniformBufferData = nullptr;
 		UINT8* uniformBufferData = nullptr;
 
 
 		UINT32 blockBinding = 0;
 		UINT32 blockBinding = 0;
@@ -467,6 +433,11 @@ namespace BansheeEngine
 		// Set border color
 		// Set border color
 		setTextureBorderColor(unit, stateProps.getBorderColor());
 		setTextureBorderColor(unit, stateProps.getBorderColor());
 
 
+		SPtr<GLSLGpuProgramCore> activeProgram = getActiveProgram(gptype);
+		GLuint glProgram = activeProgram->getGLHandle();
+
+		glProgramUniform1i(glProgram, unit, getGLTextureUnit(gptype, unit));
+
 		BS_INC_RENDER_STAT(NumSamplerBinds);
 		BS_INC_RENDER_STAT(NumSamplerBinds);
 	}
 	}
 
 

+ 1 - 0
BansheeRenderer/BansheeRenderer.vcxproj

@@ -243,6 +243,7 @@
     <ClInclude Include="Include\BsBansheeRenderer.h" />
     <ClInclude Include="Include\BsBansheeRenderer.h" />
     <ClInclude Include="Include\BsBansheeRendererFactory.h" />
     <ClInclude Include="Include\BsBansheeRendererFactory.h" />
     <ClInclude Include="Include\BsBansheeRendererPrerequisites.h" />
     <ClInclude Include="Include\BsBansheeRendererPrerequisites.h" />
+    <ClInclude Include="Include\BsRenderBeastOptions.h" />
     <ClInclude Include="Include\BsRenderTexturePool.h" />
     <ClInclude Include="Include\BsRenderTexturePool.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>

+ 3 - 0
BansheeRenderer/BansheeRenderer.vcxproj.filters

@@ -30,6 +30,9 @@
     <ClInclude Include="Include\BsRenderTexturePool.h">
     <ClInclude Include="Include\BsRenderTexturePool.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsRenderBeastOptions.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsBansheeRenderer.cpp">
     <ClCompile Include="Source\BsBansheeRenderer.cpp">

+ 34 - 1
BansheeRenderer/Include/BsBansheeRenderer.h

@@ -51,7 +51,7 @@ namespace BansheeEngine
 		};
 		};
 
 
 	public:
 	public:
-		BansheeRenderer() { }
+		BansheeRenderer();
 		~BansheeRenderer() { }
 		~BansheeRenderer() { }
 
 
 		/**
 		/**
@@ -64,6 +64,16 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void renderAll() override;
 		virtual void renderAll() override;
 
 
+		/**
+		 * @brief	Sets options used for controlling the rendering.
+		 */
+		void setOptions(const SPtr<CoreRendererOptions>& options) override;
+
+		/**
+		 * @brief	Returns current set of options used for controlling the rendering.
+		 */
+		SPtr<CoreRendererOptions> getOptions() const override;
+
 		/**
 		/**
 		 * @copydoc	Renderer::_onActivated
 		 * @copydoc	Renderer::_onActivated
 		 */
 		 */
@@ -120,6 +130,13 @@ namespace BansheeEngine
 		 */
 		 */
 		void addToRenderQueue(const SPtr<CameraHandlerCore>& proxy, RenderQueuePtr renderQueue);
 		void addToRenderQueue(const SPtr<CameraHandlerCore>& proxy, RenderQueuePtr renderQueue);
 
 
+		/**
+		 * @brief	Updates the render options on the core thread.
+		 *
+		 * @note	Core thread only.
+		 */
+		void syncRenderOptions(const RenderBeastOptions& options);
+
 		/**
 		/**
 		 * @brief	Performs rendering over all camera proxies.
 		 * @brief	Performs rendering over all camera proxies.
 		 *
 		 *
@@ -154,6 +171,18 @@ namespace BansheeEngine
 		 */
 		 */
 		SPtr<ShaderCore> createDefaultShader();
 		SPtr<ShaderCore> createDefaultShader();
 
 
+		/**
+		 * @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.
+		 *
+		 * @note	Core thread.
+		 */
+		static void setPass(const SPtr<MaterialCore>& material, UINT32 passIdx, SPtr<SamplerStateCore>* samplerOverrides);
+
 		Vector<RenderTargetData> mRenderTargets; // Core thread
 		Vector<RenderTargetData> mRenderTargets; // Core thread
 		UnorderedMap<const CameraHandlerCore*, CameraData> mCameraData; // Core thread
 		UnorderedMap<const CameraHandlerCore*, CameraData> mCameraData; // Core thread
 
 
@@ -163,6 +192,10 @@ namespace BansheeEngine
 		Vector<Matrix4> mWorldTransforms; // Core thread
 		Vector<Matrix4> mWorldTransforms; // Core thread
 		Vector<Bounds> mWorldBounds; // Core thread
 		Vector<Bounds> mWorldBounds; // Core thread
 
 
+		SPtr<RenderBeastOptions> mCoreOptions; // Core thread
+
 		LitTexRenderableController* mLitTexHandler;
 		LitTexRenderableController* mLitTexHandler;
+		SPtr<RenderBeastOptions> mOptions;
+		bool mOptionsDirty;
 	};
 	};
 }
 }

+ 1 - 0
BansheeRenderer/Include/BsBansheeRendererPrerequisites.h

@@ -21,4 +21,5 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	class LitTexRenderableController;
 	class LitTexRenderableController;
+	struct RenderBeastOptions;
 }
 }

+ 56 - 0
BansheeRenderer/Include/BsRenderBeastOptions.h

@@ -0,0 +1,56 @@
+#pragma once
+
+#include "BsBansheeRendererPrerequisites.h"
+#include "BsRenderer.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Texture filtering options for RenderBeast.
+	 */
+	enum class RenderBeastFiltering
+	{
+		Bilinear, /**< Sample linearly in X and Y directions within a texture mip level. */
+		Trilinear, /**< Sample bilinearly and also between texture mip levels to hide the mip transitions. */
+		Anisotropic /**< High quality dynamic filtering that improves quality of angled surfaces */
+	};
+
+	/**
+	 * @brief	A set of options used for controlling the 
+	 *			rendering of the RenderBeast renderer.
+	 */
+	struct BS_BSRND_EXPORT RenderBeastOptions : public CoreRendererOptions
+	{
+		/**
+		 * @brief	Type of filtering to use for all textures on scene elements.
+		 */
+		RenderBeastFiltering filtering = RenderBeastFiltering::Anisotropic;
+
+		/**
+		 * @brief	Maximum number of samples to be used when performing anisotropic
+		 *			filtering. Only relevant if ::filter is set to RenderBeastFiltering::Anisotropic.
+		 */
+		UINT32 anisotropyMax = 16;
+
+		/**
+		 * @brief	Number of samples per pixel. More samples means less aliasing but this may
+		 *			seriously increase fillrate and memory consumption on the GPU.
+		 */
+
+		UINT32 msaa = 4;
+		/** 
+		 * All colors output from shaders will be automatically converted to gamma 
+		 * space when written to render target(s). Normally used when the renderer
+		 * performs calculations in linear space.
+		 */
+		bool gammaCorrect = true; 
+
+		/**
+		 * High dynamic range allows light intensity to be more correctly recorded
+		 * when rendering by allowing for a larger range of values. The stored light
+		 * is then converted into visible colors using a tone mapping operator depending
+		 * on average scene brightness.
+		 */
+		bool hdr = true;
+	};
+}

+ 166 - 1
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -29,11 +29,18 @@
 #include "BsRenderableElement.h"
 #include "BsRenderableElement.h"
 #include "BsFrameAlloc.h"
 #include "BsFrameAlloc.h"
 #include "BsCoreObjectManager.h"
 #include "BsCoreObjectManager.h"
+#include "BsRenderBeastOptions.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	BansheeRenderer::BansheeRenderer()
+		:mOptions(bs_shared_ptr<RenderBeastOptions>()), mOptionsDirty(true)
+	{
+
+	}
+
 	const StringID& BansheeRenderer::getName() const
 	const StringID& BansheeRenderer::getName() const
 	{
 	{
 		static StringID name = "BansheeRenderer";
 		static StringID name = "BansheeRenderer";
@@ -57,6 +64,7 @@ namespace BansheeEngine
 
 
 	void BansheeRenderer::initializeCore()
 	void BansheeRenderer::initializeCore()
 	{
 	{
+		mCoreOptions = bs_shared_ptr<RenderBeastOptions>();
 		mLitTexHandler = bs_new<LitTexRenderableController>();
 		mLitTexHandler = bs_new<LitTexRenderableController>();
 
 
 		SPtr<ShaderCore> shader = createDefaultShader();
 		SPtr<ShaderCore> shader = createDefaultShader();
@@ -112,6 +120,8 @@ namespace BansheeEngine
 				if (renElement.material == nullptr)
 				if (renElement.material == nullptr)
 					renElement.material = mDummyMaterial;
 					renElement.material = mDummyMaterial;
 
 
+				renElement.samplerOverrides = nullptr; // TODO
+
 				if (renderableData.controller != nullptr)
 				if (renderableData.controller != nullptr)
 					renderableData.controller->initializeRenderElem(renElement);
 					renderableData.controller->initializeRenderElem(renElement);
 			}
 			}
@@ -169,6 +179,17 @@ namespace BansheeEngine
 		mCameraData.erase(camera);
 		mCameraData.erase(camera);
 	}
 	}
 
 
+	void BansheeRenderer::setOptions(const SPtr<CoreRendererOptions>& options)
+	{
+		mOptions = std::static_pointer_cast<RenderBeastOptions>(options);
+		mOptionsDirty = true;
+	}
+
+	SPtr<CoreRendererOptions> BansheeRenderer::getOptions() const
+	{
+		return mOptions;
+	}
+
 	void BansheeRenderer::renderAll() 
 	void BansheeRenderer::renderAll() 
 	{
 	{
 		// Populate direct draw lists
 		// Populate direct draw lists
@@ -209,6 +230,12 @@ namespace BansheeEngine
 		// Sync all dirty sim thread CoreObject data to core thread
 		// Sync all dirty sim thread CoreObject data to core thread
 		CoreObjectManager::instance().syncToCore(gCoreAccessor());
 		CoreObjectManager::instance().syncToCore(gCoreAccessor());
 
 
+		if (mOptionsDirty)
+		{
+			gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::syncRenderOptions, this, *mOptions));
+			mOptionsDirty = false;
+		}
+
 		gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::renderAllCore, this, gTime().getTime()));
 		gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::renderAllCore, this, gTime().getTime()));
 	}
 	}
 
 
@@ -218,6 +245,20 @@ namespace BansheeEngine
 		cameraRenderQueue->add(*renderQueue);
 		cameraRenderQueue->add(*renderQueue);
 	}
 	}
 
 
+	void BansheeRenderer::syncRenderOptions(const RenderBeastOptions& options)
+	{
+		bool filteringChanged = mCoreOptions->filtering != options.filtering;
+		if (options.filtering == RenderBeastFiltering::Anisotropic)
+			filteringChanged |= mCoreOptions->anisotropyMax != options.anisotropyMax;
+
+		if (filteringChanged)
+		{
+			// TODO - Rebuild sample overrides
+		}
+
+		*mCoreOptions = options;
+	}
+
 	void BansheeRenderer::renderAllCore(float time)
 	void BansheeRenderer::renderAllCore(float time)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
@@ -392,7 +433,12 @@ namespace BansheeEngine
 		{
 		{
 			SPtr<MaterialCore> material = iter->material;
 			SPtr<MaterialCore> material = iter->material;
 
 
-			setPass(material, iter->passIdx);
+			RenderableElement* renderable = iter->renderElem;
+			if (renderable != nullptr && renderable->samplerOverrides != nullptr)
+				setPass(material, iter->passIdx, renderable->samplerOverrides[iter->passIdx]);
+			else
+				setPass(material, iter->passIdx, nullptr);
+
 			draw(iter->mesh, iter->subMesh);
 			draw(iter->mesh, iter->subMesh);
 		}
 		}
 
 
@@ -411,6 +457,125 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	void BansheeRenderer::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx, SPtr<SamplerStateCore>* samplerOverrides)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		SPtr<PassCore> pass = material->getPass(passIdx);
+		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
+
+		struct StageData
+		{
+			GpuProgramType type;
+			bool enable;
+			SPtr<GpuParamsCore> params;
+			SPtr<GpuProgramCore> program;
+		};
+
+		const UINT32 numStages = 6;
+		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()
+			}
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			if (stage.enable)
+			{
+				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[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
+				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
+		if (pass->getBlendState() != nullptr)
+			rs.setBlendState(pass->getBlendState());
+		else
+			rs.setBlendState(BlendStateCore::getDefault());
+
+		if (pass->getDepthStencilState() != nullptr)
+			rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue());
+		else
+			rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue());
+
+		if (pass->getRasterizerState() != nullptr)
+			rs.setRasterizerState(pass->getRasterizerState());
+		else
+			rs.setRasterizerState(RasterizerStateCore::getDefault());
+	}
+
 	SPtr<ShaderCore> BansheeRenderer::createDefaultShader()
 	SPtr<ShaderCore> BansheeRenderer::createDefaultShader()
 	{
 	{
 		StringID rsName = RenderAPICore::instance().getName();
 		StringID rsName = RenderAPICore::instance().getName();

+ 18 - 0
BansheeUtility/Include/BsColor.h

@@ -262,3 +262,21 @@ namespace BansheeEngine
 
 
 	BS_ALLOW_MEMCPY_SERIALIZATION(Color);
 	BS_ALLOW_MEMCPY_SERIALIZATION(Color);
 }
 }
+
+/**
+ * @brief	Hash value generator for Color.
+ */
+template<> 
+struct std::hash<BansheeEngine::Color>
+{
+	size_t operator()(const BansheeEngine::Color& color) const
+	{
+		size_t hash = 0;
+		BansheeEngine::hash_combine(hash, color.r);
+		BansheeEngine::hash_combine(hash, color.g);
+		BansheeEngine::hash_combine(hash, color.b);
+		BansheeEngine::hash_combine(hash, color.a);
+
+		return hash;
+	}
+};

+ 1 - 1
BansheeUtility/Include/BsString.h

@@ -934,7 +934,7 @@ namespace BansheeEngine
 }
 }
 
 
 /**
 /**
- * @brief	Hash value generator for SString.
+ * @brief	Hash value generator for String.
  */
  */
 template<> 
 template<> 
 struct std::hash<BansheeEngine::String>
 struct std::hash<BansheeEngine::String>

+ 12 - 7
TODOExperimentation.txt

@@ -7,14 +7,19 @@ Document RenderTargetPool and potentially move it outside of BansheeRenderer
 Implement light added/removed/updated in BansheeRenderer
 Implement light added/removed/updated in BansheeRenderer
 Load up and set up a test-bed with Ribek's scene
 Load up and set up a test-bed with Ribek's scene
 
 
-Need cone to use when rendering spot light
+Texture filtering changes:
+ - Each sampler state gets a unique ID
+ - I store this ID along with the sampler override
+ - Every frame I run as pass over all renderable elements a check if their override
+   sampler states match the original IDs, and recreate them if not (do this at start of rendering in renderAll core)
+     - TODO - This can be potentially slower than needed. Optiomally I'd like to figure out a better way.
+ - Whenever render settings are marked as dirty and filtering settings have changed run over all elements recreating their
+   sampler state overrides
+ - Issue with state caching: State caching doesn't work when deserializing
+
+Rename BansheeRenderer to RenderBeast
 
 
-Renderer needs options:
- - Sample count
- - sRGB output
- - HDR rendering
- - Texture filtering + anisotropic amount
- - These need to properly recreate gbuffer and other objects when they change
+Need cone to use when rendering spot light
 
 
 Create a basic GBuffer - albedo, normal, depth
 Create a basic GBuffer - albedo, normal, depth
  - Using HDR formats where needed
  - Using HDR formats where needed