Ver Fonte

Added support for renderer tasks
Changed how reflection probes are generated
Reflection probe filtered map serialization implemented

BearishSun há 8 anos atrás
pai
commit
39ee300919
27 ficheiros alterados com 554 adições e 252 exclusões
  1. 2 0
      Source/BansheeCore/CMakeSources.cmake
  2. 3 3
      Source/BansheeCore/Include/BsCReflectionProbe.h
  3. 1 1
      Source/BansheeCore/Include/BsCamera.h
  4. 71 0
      Source/BansheeCore/Include/BsIBLUtility.h
  5. 2 2
      Source/BansheeCore/Include/BsLight.h
  6. 1 1
      Source/BansheeCore/Include/BsLightProbeVolume.h
  7. 51 32
      Source/BansheeCore/Include/BsReflectionProbe.h
  8. 12 1
      Source/BansheeCore/Include/BsReflectionProbeRTTI.h
  9. 1 1
      Source/BansheeCore/Include/BsRenderable.h
  10. 102 1
      Source/BansheeCore/Include/BsRenderer.h
  11. 1 1
      Source/BansheeCore/Include/BsSkybox.h
  12. 10 0
      Source/BansheeCore/Source/BsCReflectionProbe.cpp
  13. 4 0
      Source/BansheeCore/Source/BsCoreApplication.cpp
  14. 14 0
      Source/BansheeCore/Source/BsIBLUtility.cpp
  15. 89 39
      Source/BansheeCore/Source/BsReflectionProbe.cpp
  16. 126 0
      Source/BansheeCore/Source/BsRenderer.cpp
  17. 0 2
      Source/BansheeEngine/CMakeSources.cmake
  18. 2 0
      Source/RenderBeast/CMakeSources.cmake
  19. 0 3
      Source/RenderBeast/Include/BsImageBasedLighting.h
  20. 5 23
      Source/RenderBeast/Include/BsRenderBeast.h
  21. 13 46
      Source/RenderBeast/Include/BsRenderBeastIBLUtility.h
  22. 1 4
      Source/RenderBeast/Include/BsRendererScene.h
  23. 0 3
      Source/RenderBeast/Source/BsImageBasedLighting.cpp
  24. 3 3
      Source/RenderBeast/Source/BsLightProbes.cpp
  25. 23 62
      Source/RenderBeast/Source/BsRenderBeast.cpp
  26. 9 10
      Source/RenderBeast/Source/BsRenderBeastIBLUtility.cpp
  27. 8 14
      Source/RenderBeast/Source/BsRendererScene.cpp

+ 2 - 0
Source/BansheeCore/CMakeSources.cmake

@@ -102,6 +102,7 @@ set(BS_BANSHEECORE_INC_RENDERER
 	"Include/BsReflectionProbe.h"
 	"Include/BsSkybox.h"
 	"Include/BsLightProbeVolume.h"
+	"Include/BsIBLUtility.h"
 )
 
 set(BS_BANSHEECORE_SRC_LOCALIZATION
@@ -378,6 +379,7 @@ set(BS_BANSHEECORE_SRC_RENDERER
 	"Source/BsReflectionProbe.cpp"
 	"Source/BsSkybox.cpp"
 	"Source/BsLightProbeVolume.cpp"
+	"Source/BsIBLUtility.cpp"
 )
 
 set(BS_BANSHEECORE_SRC_RESOURCES

+ 3 - 3
Source/BansheeCore/Include/BsCReflectionProbe.h

@@ -64,9 +64,9 @@ namespace bs
 		/** @copydoc ReflectionProbe::getBounds */
 		Sphere getBounds() const;
 
-		/** @copydoc ReflectionProbe::generate */
-		BS_SCRIPT_EXPORT(n:Generate)
-		void generate() { mInternal->generate(); }
+		/** @copydoc ReflectionProbe::capture */
+		BS_SCRIPT_EXPORT(n:Capture)
+		void capture() { mInternal->capture(); }
 
 		/** @name Internal
 		 *  @{

+ 1 - 1
Source/BansheeCore/Include/BsCamera.h

@@ -466,7 +466,7 @@ namespace bs
 
 	/** @} */
 
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 

+ 71 - 0
Source/BansheeCore/Include/BsIBLUtility.h

@@ -0,0 +1,71 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsModule.h"
+
+namespace bs { namespace ct
+{
+	/** @addtogroup Renderer-Internal
+	 *  @{
+	 */
+
+	/** Helper class that handles generation and processing of textures used for image based lighting. */
+	class BS_CORE_EXPORT IBLUtility : public Module<IBLUtility>
+	{
+	public:
+		/**
+		 * Performs filtering on the cubemap, populating its mip-maps with filtered values that can be used for
+		 * evaluating specular reflections.
+		 * 
+		 * @param[in, out]	cubemap		Cubemap to filter. Its mip level 0 will be read, filtered and written into
+		 *								other mip levels.
+		 * @param[in]		scratch		Temporary cubemap texture to use for the filtering process. Must match the size of
+		 *								the source cubemap. Provide null to automatically create a scratch cubemap.
+		 */
+		virtual void filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch) const = 0;
+
+		/**
+		 * Performs filtering on the cubemap, populating the output cubemap with values that can be used for evaluating
+		 * irradiance for use in diffuse lighting. Uses order-5 SH (25 coefficients) and outputs the values in the form of
+		 * a cubemap.
+		 * 
+		 * @param[in]		cubemap		Cubemap to filter. Its mip level 0 will be used as source.
+		 * @param[in]		output		Output cubemap to store the irradiance data in.
+		 */
+		virtual void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output) const = 0;
+
+		/**
+		 * Performs filtering on the cubemap, populating the output cubemap with values that can be used for evaluating
+		 * irradiance for use in diffuse lighting. Uses order-5 SH (9 coefficients) and outputs the values in the form of
+		 * a cubemap.
+		 * 
+		 * @param[in]		cubemap		Cubemap to filter. Its mip level 0 will be used as source.
+		 * @param[in]		output		Output buffer in which to place the results. Must be allocated using 
+		 *								IrradianceReduceMat<ORDER>::createOutputBuffer();
+		 * @param[in]		outputIdx	Index in the output buffer at which to write the output coefficients to.
+		 */
+		virtual void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
+			UINT32 outputIdx) const = 0;
+
+		/**
+		 * Scales a cubemap and outputs it in the destination texture, using hardware acceleration. If both textures are the
+		 * same size, performs a copy instead.
+		 *
+		 * @param[in]   src				Source cubemap to scale.
+		 * @param[in]   srcMip			Determines which mip level of the source texture to scale.
+		 * @param[in]   dst				Desination texture to output the scaled data to. Must be usable as a render target.
+		 * @param[in]   dstMip			Determines which mip level of the destination texture to scale.
+		 */
+		virtual void scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip) const = 0;
+
+		static const UINT32 REFLECTION_CUBEMAP_SIZE;
+		static const UINT32 IRRADIANCE_CUBEMAP_SIZE;
+	};
+
+	/**	Provides easy access to IBLUtility. */
+	BS_CORE_EXPORT const IBLUtility& gIBLUtility();
+
+	/** @} */
+}}

+ 2 - 2
Source/BansheeCore/Include/BsLight.h

@@ -12,7 +12,7 @@
 
 namespace bs
 {
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 
@@ -221,7 +221,7 @@ namespace bs
 	};
 
 	/** @} */
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 

+ 1 - 1
Source/BansheeCore/Include/BsLightProbeVolume.h

@@ -58,7 +58,7 @@ namespace bs
 	};
 
 	/** @} */
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 

+ 51 - 32
Source/BansheeCore/Include/BsReflectionProbe.h

@@ -11,7 +11,7 @@
 
 namespace bs
 {
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 
@@ -135,48 +135,50 @@ namespace bs
 		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
 	};
 
-	/** Templated base class for both core and sim thread implementations of a reflection probe. */
-	template<bool Core>
-	class BS_CORE_EXPORT TReflectionProbe : public ReflectionProbeBase
+	/** @} */
+	/** @addtogroup Renderer-Internal
+	 *  @{
+	 */
+
+	namespace ct 
 	{
-		typedef typename TTextureType<Core>::Type TextureType;
+		class RendererTask;
+		class ReflectionProbe; 
+	}
 
+	/**
+	 * Specifies a location at which a pre-computed texture containing scene radiance will be generated. This texture will
+	 * then be used by the renderer to provide specular reflections.
+	 */
+	class BS_CORE_EXPORT ReflectionProbe : public IReflectable, public CoreObject, public ReflectionProbeBase
+	{
 	public:
-		TReflectionProbe();
-		TReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents);
-		virtual ~TReflectionProbe() { }
-
 		/** 
 		 * Allows you assign a custom texture to use as a reflection map. This will disable automatic generation of
 		 * reflections. To re-enable auto-generation call this with a null parameter.
 		 */
-		void setCustomTexture(const TextureType& texture) { mCustomTexture = texture; _markCoreDirty(); }
+		void setCustomTexture(const HTexture& texture) { mCustomTexture = texture; filter(); }
 
 		/** Gets the custom texture assigned through setCustomTexture(). */
-		TextureType getCustomTexture() const { return mCustomTexture; }
-
-		/** Forces the reflection probe to regenerate its texture. Call is ignored if the probe uses a custom texture. */
-		void generate();
-
-	protected:
-		TextureType mCustomTexture;
-	};
+		HTexture getCustomTexture() const { return mCustomTexture; }
 
+		/** 
+		 * Returns a pre-filtered texture that is generated either from the provided custom texture, or from scene capture.
+		 */
+		SPtr<Texture> getFilteredTexture() const { return mFilteredTexture; }
 
-	/** @} */
-	/** @addtogroup Renderer-Engine-Internal
-	 *  @{
-	 */
+		/** 
+		 * Captures the scene at the current location and generates a filtered reflection cubemap. No action is taken
+		 * if a custom texture is set.
+		 */
+		void capture();
 
-	namespace ct { class ReflectionProbe; }
+		/** 
+		 * Filters the custom texture, making it usable for rendering. Called automatically when custom texture changes. If 
+		 * no custom texture is set, no action is taken.
+		 */
+		void filter();
 
-	/**
-	 * Specifies a location at which a pre-computed texture containing scene radiance will be generated. This texture will
-	 * then be used by the renderer to provide specular reflections.
-	 */
-	class BS_CORE_EXPORT ReflectionProbe : public IReflectable, public CoreObject, public TReflectionProbe<false>
-	{
-	public:
 		/**	Retrieves an implementation of the reflection probe usable only from the core thread. */
 		SPtr<ct::ReflectionProbe> getCore() const;
 
@@ -222,10 +224,20 @@ namespace bs
 		/** @copydoc CoreObject::syncToCore */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
 
+		/** 
+		 * Captures the scene color at current probe location and generates a filtered map. If a custom texture is set then
+		 * it will be filtered, instead of capturing scene color.
+		 */
+		void captureAndFilter();
+
 		/**	Creates a light with without initializing it. Used for serialization. */
 		static SPtr<ReflectionProbe> createEmpty();
 
 		UINT32 mLastUpdateHash;
+		HTexture mCustomTexture;
+
+		SPtr<ct::RendererTask> mRendererTask;
+		SPtr<Texture> mFilteredTexture;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -242,7 +254,7 @@ namespace bs
 	namespace ct
 	{
 	/** Core thread usable version of a bs::ReflectionProbe */
-	class BS_CORE_EXPORT ReflectionProbe : public CoreObject, public TReflectionProbe<true>
+	class BS_CORE_EXPORT ReflectionProbe : public CoreObject, public ReflectionProbeBase
 	{
 	public:
 		~ReflectionProbe();
@@ -252,10 +264,16 @@ namespace bs
 
 		/**	Retrieves an ID that can be used for uniquely identifying this object by the renderer. */
 		UINT32 getRendererId() const { return mRendererId; }
+
+		/** 
+		 * Returns a pre-filtered texture that is generated either from the provided custom texture, or from scene capture.
+		 */
+		SPtr<Texture> getFilteredTexture() const { return mFilteredTexture; }
 	protected:
 		friend class bs::ReflectionProbe;
 
-		ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents);
+		ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents, 
+			const SPtr<Texture>& filteredTexture);
 
 		/** @copydoc CoreObject::initialize */
 		void initialize() override;
@@ -264,6 +282,7 @@ namespace bs
 		void syncToCore(const CoreSyncData& data) override;
 
 		UINT32 mRendererId;
+		SPtr<Texture> mFilteredTexture;
 	};
 	}
 

+ 12 - 1
Source/BansheeCore/Include/BsReflectionProbeRTTI.h

@@ -5,6 +5,7 @@
 #include "BsCorePrerequisites.h"
 #include "BsRTTIType.h"
 #include "BsReflectionProbe.h"
+#include "BsRenderer.h"
 
 namespace bs
 {
@@ -26,12 +27,22 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(mTransitionDistance, 6)
 			BS_RTTI_MEMBER_REFL(mCustomTexture, 7)
 			BS_RTTI_MEMBER_PLAIN(mUUID, 8)
+			BS_RTTI_MEMBER_REFLPTR(mFilteredTexture, 9)
 		BS_END_RTTI_MEMBERS
 	public:
 		ReflectionProbeRTTI()
 			:mInitMembers(this)
 		{ }
 
+		void onSerializationStarted(IReflectable* obj, const UnorderedMap<String, UINT64>& params) override
+		{
+			ReflectionProbe* probe = static_cast<ReflectionProbe*>(obj);
+
+			// Force the renderer task to complete, so the filtered texture is up to date
+			if (probe->mRendererTask != nullptr)
+				probe->mRendererTask->wait();
+		}
+
 		void onDeserializationEnded(IReflectable* obj, const UnorderedMap<String, UINT64>& params) override
 		{
 			// Note: Since this is a CoreObject I should call initialize() right after deserialization,
@@ -59,4 +70,4 @@ namespace bs
 
 	/** @} */
 	/** @endcond */
-}
+}

+ 1 - 1
Source/BansheeCore/Include/BsRenderable.h

@@ -183,7 +183,7 @@ namespace bs
 
 	/** @} */
 
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 

+ 102 - 1
Source/BansheeCore/Include/BsRenderer.h

@@ -14,6 +14,8 @@ namespace bs
 
 	namespace ct
 	{
+	class RendererTask;
+
 	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
@@ -46,6 +48,9 @@ namespace bs
 		/** Initializes the renderer. Must be called before using the renderer. */
 		virtual void initialize() { }
 
+		/** Called every frame. Triggers render task callbacks. */
+		void update();
+
 		/**	Cleans up the renderer. Must be called before the renderer is deleted. */
 		virtual void destroy() { }
 
@@ -133,7 +138,7 @@ namespace bs
 		 *
 		 * @note	Core thread.
 		 */
-		virtual void notifyReflectionProbeUpdated(ReflectionProbe* probe) { }
+		virtual void notifyReflectionProbeUpdated(ReflectionProbe* probe, bool texture) { }
 
 		/**
 		 * Called whenever a reflection probe is destroyed.
@@ -184,6 +189,17 @@ namespace bs
 		 */
 		virtual void notifySkyboxRemoved(Skybox* skybox) { }
 
+		/** 
+		 * Captures the scene at the specified location into a cubemap. 
+		 * 
+		 * @param[in]	cubemap		Cubemap to store the results in.
+		 * @param[in]	position	Position to capture the scene at.
+		 * @param[in]	hdr			If true scene will be captured in a format that supports high dynamic range.
+		 *
+		 * @note	Core thread.
+		 */
+		virtual void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr) = 0;
+
 		/**
 		 * Creates a new empty renderer mesh data.
 		 *
@@ -218,6 +234,13 @@ namespace bs
 		 */
 		void removePlugin(RendererExtension* plugin) { mCallbacks.erase(plugin); }
 
+		/**
+		 * Registers a new task for execution on the core thread.
+		 * 
+		 * @note	Thread safe.
+		 */
+		void addTask(const SPtr<RendererTask>& task);
+
 		/**	Sets options used for controlling the rendering. */
 		virtual void setOptions(const SPtr<RendererOptions>& options) { }
 
@@ -225,6 +248,8 @@ namespace bs
 		virtual SPtr<RendererOptions> getOptions() const { return SPtr<RendererOptions>(); }
 
 	protected:
+		friend class RendererTask;
+
 		/**	Contains information about a render callback. */
 		struct RenderCallbackData
 		{
@@ -232,14 +257,90 @@ namespace bs
 			std::function<void()> callback;
 		};
 
+		/**
+		 * Executes all renderer tasks queued for this frame.
+		 *
+		 * @param[in]	forceAll	If true, multi-frame tasks will be forced to execute fully within this call.
+		 * 
+		 * @note	Core thread.
+		 */
+		void processTasks(bool forceAll);
+
+		/**
+		 * Executes the provided renderer task.
+		 *
+		 * @param[in]	task		Task to execute.
+		 * @param[in]	forceAll	If true, multi-frame tasks will be forced to execute fully within this call.
+		 * 
+		 * @note	Core thread.
+		 */
+		void processTask(RendererTask& task, bool forceAll);
+
 		/** Callback to trigger when comparing the order in which renderer extensions are called. */
 		static bool compareCallback(const RendererExtension* a, const RendererExtension* b);
 
 		Set<RendererExtension*, std::function<bool(const RendererExtension*, const RendererExtension*)>> mCallbacks;
+
+		Vector<SPtr<RendererTask>> mQueuedTasks; // Sim & core thread
+		Vector<SPtr<RendererTask>> mUnresolvedTasks; // Sim thread
+		Vector<SPtr<RendererTask>> mRemainingUnresolvedTasks; // Sim thread
+		Vector<SPtr<RendererTask>> mRunningTasks; // Core thread
+		Vector<SPtr<RendererTask>> mRemainingTasks; // Core thread
+		Mutex mTaskMutex;
 	};
 
 	/**	Provides easy access to Renderer. */
 	SPtr<Renderer> BS_CORE_EXPORT gRenderer();
 
+	/**
+	 * Task that represents an asynchonous operation queued for execution on the core thread. All such tasks are executed
+	 * before main rendering happens, every frame.
+	 *
+	 * @note	Thread safe except where stated otherwise.
+	 */
+	class BS_CORE_EXPORT RendererTask
+	{
+		struct PrivatelyConstruct {};
+
+	public:
+		RendererTask(const PrivatelyConstruct& dummy, const String& name, std::function<bool()> taskWorker);
+
+		/**
+		 * Creates a new task. Task should be provided to Renderer in order for it to start.
+		 *
+		 * @param[in]	name		Name you can use to more easily identify the task.
+		 * @param[in]	taskWorker	Worker method that does all of the work in the task. Tasks can run over the course of
+		 *							multiple frames, in which case this method should return false (if there's more
+		 *							work to be done), or true (if the task has completed).
+		 */
+		static SPtr<RendererTask> create(const String& name, std::function<bool()> taskWorker);
+
+		/** Returns true if the task has completed. */
+		bool isComplete() const;
+
+		/**	Returns true if the task has been canceled. */
+		bool isCanceled() const;
+
+		/** Blocks the current thread until the task has completed. */
+		void wait();
+
+		/** Cancels the task and removes it from the Renderer's queue. */
+		void cancel();
+
+		/** 
+		 * Callback triggered on the sim thread, when the task completes. Is not triggered if the task is cancelled.
+		 *
+		 * @note	Sim thread only.
+		 */
+		Event<void()> onComplete;
+
+	private:
+		friend class Renderer;
+
+		String mName;
+		std::function<bool()> mTaskWorker;
+		std::atomic<UINT32> mState; /**< 0 - Inactive, 1 - In progress, 2 - Completed, 3 - Canceled */
+	};
+
 	/** @} */
 }}

+ 1 - 1
Source/BansheeCore/Include/BsSkybox.h

@@ -80,7 +80,7 @@ namespace bs
 	};
 
 	/** @} */
-	/** @addtogroup Renderer-Engine-Internal
+	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
 

+ 10 - 0
Source/BansheeCore/Source/BsCReflectionProbe.cpp

@@ -41,6 +41,16 @@ namespace bs
 			mInternal = ReflectionProbe::createBox(Vector3::ONE);
 
 		gSceneManager()._registerReflectionProbe(mInternal, sceneObject());
+
+		// If filtered texture doesn't exist, ensure it is generated
+		SPtr<Texture> filteredTexture = mInternal->getFilteredTexture();
+		if(filteredTexture == nullptr)
+		{
+			if (mInternal->getCustomTexture())
+				mInternal->filter();
+			else
+				mInternal->capture();
+		}
 	}
 
 	void CReflectionProbe::onDestroyed()

+ 4 - 0
Source/BansheeCore/Source/BsCoreApplication.cpp

@@ -238,6 +238,10 @@ namespace bs
 			// Send out resource events in case any were loaded/destroyed/modified
 			ResourceListenerManager::instance().update();
 
+			// Trigger any renderer task callbacks (should be done before scene object update, or core sync, so objects have
+			// a chance to respond to the callback).
+			RendererManager::instance().getActive()->update();
+
 			gSceneManager()._updateCoreObjectTransforms();
 			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
 

+ 14 - 0
Source/BansheeCore/Source/BsIBLUtility.cpp

@@ -0,0 +1,14 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsIBLUtility.h"
+
+namespace bs { namespace ct
+{
+	const UINT32 IBLUtility::REFLECTION_CUBEMAP_SIZE = 256;
+	const UINT32 IBLUtility::IRRADIANCE_CUBEMAP_SIZE = 32;
+
+	const IBLUtility& gIBLUtility()
+	{
+		return IBLUtility::instance();
+	}
+}}

+ 89 - 39
Source/BansheeCore/Source/BsReflectionProbe.cpp

@@ -7,6 +7,7 @@
 #include "BsTexture.h"
 #include "BsRenderer.h"
 #include "BsUUID.h"
+#include "BsIBLUtility.h"
 
 namespace bs
 {
@@ -33,37 +34,94 @@ namespace bs
 		}
 	}
 
-	template <bool Core>
-	TReflectionProbe<Core>::TReflectionProbe()
-		:ReflectionProbeBase()
-	{ }
+	ReflectionProbe::ReflectionProbe()
+		:mLastUpdateHash(0)
+	{
 
-	template <bool Core>
-	TReflectionProbe<Core>::TReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
-		: ReflectionProbeBase(type, radius, extents)
-	{ }
+	}
 
-	template <bool Core>
-	void TReflectionProbe<Core>::generate()
+	ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
+		: ReflectionProbeBase(type, radius, extents), mLastUpdateHash(0)
 	{
-		if (mCustomTexture != nullptr)
-			_markCoreDirty();
+		// Calling virtual method is okay here because this is the most derived type
+		updateBounds();
 	}
 
-	template class TReflectionProbe<true>;
-	template class TReflectionProbe<false>;
+	void ReflectionProbe::capture()
+	{
+		if (mCustomTexture != nullptr)
+			return;
 
-	ReflectionProbe::ReflectionProbe()
-		:mLastUpdateHash(0)
+		captureAndFilter();
+	}
+
+	void ReflectionProbe::filter()
 	{
+		if (mCustomTexture == nullptr)
+			return;
 
+		captureAndFilter();
 	}
 
-	ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
-		: TReflectionProbe(type, radius, extents), mLastUpdateHash(0)
+	void ReflectionProbe::captureAndFilter()
 	{
-		// Calling virtual method is okay here because this is the most derived type
-		updateBounds();
+		// If previous rendering task exists, cancel it
+		if (mRendererTask != nullptr)
+			mRendererTask->cancel();
+
+		TEXTURE_DESC cubemapDesc;
+		cubemapDesc.type = TEX_TYPE_CUBE_MAP;
+		cubemapDesc.format = PF_FLOAT_R11G11B10;
+		cubemapDesc.width = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE;
+		cubemapDesc.height = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE;
+		cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format);
+		cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
+
+		mFilteredTexture = Texture::_createPtr(cubemapDesc);
+
+		auto renderComplete = [this]()
+		{
+			mRendererTask = nullptr;
+		};
+
+		SPtr<ct::ReflectionProbe> coreProbe = getCore();
+		SPtr<ct::Texture> coreTexture = mFilteredTexture->getCore();
+
+		if (mCustomTexture == nullptr)
+		{
+			auto renderReflProbe = [coreTexture, coreProbe]()
+			{
+				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), true);
+				ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
+
+				coreProbe->mFilteredTexture = coreTexture;
+				ct::gRenderer()->notifyReflectionProbeUpdated(coreProbe.get(), true);
+
+				return true;
+			};
+
+			mRendererTask = ct::RendererTask::create("ReflProbeRender", renderReflProbe);
+		}
+		else
+		{
+			SPtr<ct::Texture> coreCustomTex = mCustomTexture->getCore();
+			auto filterReflProbe = [coreCustomTex, coreTexture, coreProbe]()
+			{
+				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), true);
+				ct::gIBLUtility().scaleCubemap(coreCustomTex, 0, coreTexture, 0);
+				ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
+
+				coreProbe->mFilteredTexture = coreTexture;
+				ct::gRenderer()->notifyReflectionProbeUpdated(coreProbe.get(), true);
+
+				return true;
+			};
+
+			mRendererTask = ct::RendererTask::create("ReflProbeRender", filterReflProbe);
+		}
+
+		mRendererTask->onComplete.connect(renderComplete);
+		ct::gRenderer()->addTask(mRendererTask);
 	}
 
 	SPtr<ct::ReflectionProbe> ReflectionProbe::getCore() const
@@ -104,7 +162,12 @@ namespace bs
 
 	SPtr<ct::CoreObject> ReflectionProbe::createCore() const
 	{
-		ct::ReflectionProbe* probe = new (bs_alloc<ct::ReflectionProbe>()) ct::ReflectionProbe(mType, mRadius, mExtents);
+		SPtr<ct::Texture> filteredTexture;
+		if (mFilteredTexture != nullptr)
+			filteredTexture = mFilteredTexture->getCore();
+
+		ct::ReflectionProbe* probe = new (bs_alloc<ct::ReflectionProbe>()) ct::ReflectionProbe(mType, mRadius, mExtents, 
+			filteredTexture);
 		SPtr<ct::ReflectionProbe> probePtr = bs_shared_ptr<ct::ReflectionProbe>(probe);
 		probePtr->mUUID = mUUID;
 		probePtr->_setThisPtr(probePtr);
@@ -143,14 +206,6 @@ namespace bs
 		dataPtr = rttiWriteElem(mBounds, dataPtr);
 		dataPtr = rttiWriteElem(mUUID, dataPtr);
 
-		SPtr<ct::Texture>* customTexture = new (dataPtr)SPtr<ct::Texture>();
-		if (mCustomTexture.isLoaded(false))
-			*customTexture = mCustomTexture->getCore();
-		else
-			*customTexture = nullptr;
-
-		dataPtr += sizeof(SPtr<ct::Texture>);
-
 		return CoreSyncData(buffer, size);
 	}
 
@@ -184,8 +239,9 @@ namespace bs
 
 	namespace ct
 	{
-	ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
-			: TReflectionProbe(type, radius, extents), mRendererId(0)
+	ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents, 
+		const SPtr<Texture>& filteredTexture)
+		: ReflectionProbeBase(type, radius, extents), mRendererId(0), mFilteredTexture(filteredTexture)
 	{
 
 	}
@@ -223,18 +279,12 @@ namespace bs
 		dataPtr = rttiReadElem(mBounds, dataPtr);
 		dataPtr = rttiReadElem(mUUID, dataPtr);
 
-		SPtr<Texture>* texture = (SPtr<Texture>*)dataPtr;
-
-		mCustomTexture = *texture;
-		texture->~SPtr<Texture>();
-		dataPtr += sizeof(SPtr<Texture>);
-
 		updateBounds();
 
 		if (dirtyFlags == (UINT32)ReflectionProbeDirtyFlag::Transform)
 		{
 			if (mIsActive)
-				gRenderer()->notifyReflectionProbeUpdated(this);
+				gRenderer()->notifyReflectionProbeUpdated(this, false);
 		}
 		else
 		{
@@ -262,4 +312,4 @@ namespace bs
 		}
 	}
 
-}}
+}}

+ 126 - 0
Source/BansheeCore/Source/BsRenderer.cpp

@@ -7,6 +7,8 @@
 #include "BsMaterial.h"
 #include "BsRendererExtension.h"
 #include "BsRendererManager.h"
+#include "BsCoreObjectManager.h"
+#include "BsSceneManager.h"
 
 namespace bs { namespace ct
 {
@@ -40,8 +42,132 @@ namespace bs { namespace ct
 			return (UINT32)a->getLocation() < (UINT32)b->getLocation();
 	}
 
+	void Renderer::update()
+	{
+		for(auto& entry : mUnresolvedTasks)
+		{
+			if (entry->isComplete())
+				entry->onComplete();
+			else if (!entry->isCanceled())
+				mRemainingUnresolvedTasks.push_back(entry);
+		}
+
+		mUnresolvedTasks.clear();
+		std::swap(mRemainingUnresolvedTasks, mUnresolvedTasks);
+	}
+
+	void Renderer::addTask(const SPtr<RendererTask>& task)
+	{
+		Lock lock(mTaskMutex);
+
+		assert(task->mState != 1 && "Task is already executing, it cannot be executed again until it finishes.");
+		task->mState.store(0); // Reset state in case the task is getting re-queued
+
+		mQueuedTasks.push_back(task);
+		mUnresolvedTasks.push_back(task);
+	}
+
+	void Renderer::processTasks(bool forceAll)
+	{
+		// Move all tasks to the core thread queue
+		{
+			Lock lock(mTaskMutex);
+
+			mRunningTasks.insert(mRunningTasks.end(), mQueuedTasks.begin(), mQueuedTasks.end());
+			mQueuedTasks.clear();
+		}
+
+		do
+		{
+			for (auto& entry : mRunningTasks)
+			{
+				if (entry->isCanceled() || entry->isComplete())
+					continue;
+
+				entry->mState.store(1);
+
+				bool complete = entry->mTaskWorker();
+				if (!complete)
+					mRemainingTasks.push_back(entry);
+				else
+					entry->mState.store(2);
+			}
+
+			mRunningTasks.clear();
+			std::swap(mRemainingTasks, mRunningTasks);
+		} while (forceAll && !mRunningTasks.empty());
+	}
+
+	void Renderer::processTask(RendererTask& task, bool forceAll)
+	{
+		// Move all tasks to the core thread queue
+		{
+			Lock lock(mTaskMutex);
+
+			mRunningTasks.insert(mRunningTasks.end(), mQueuedTasks.begin(), mQueuedTasks.end());
+			mQueuedTasks.clear();
+		}
+
+		bool complete = task.isCanceled() || task.isComplete();
+		while (!complete)
+		{
+			task.mState.store(1);
+
+			complete = task.mTaskWorker();
+			if (complete)
+				task.mState.store(2);
+
+			if (!forceAll)
+				break;
+		}
+	}
+
 	SPtr<Renderer> gRenderer()
 	{
 		return std::static_pointer_cast<Renderer>(RendererManager::instance().getActive());
 	}
+
+	RendererTask::RendererTask(const PrivatelyConstruct& dummy, const String& name, std::function<bool()> taskWorker) 
+		:mName(name), mTaskWorker(taskWorker)
+	{ }
+
+	SPtr<RendererTask> RendererTask::create(const String& name, std::function<bool()> taskWorker)
+	{
+		return bs_shared_ptr_new<RendererTask>(PrivatelyConstruct(), name, taskWorker);
+	}
+
+	bool RendererTask::isComplete() const
+	{
+		return mState.load() == 2;
+	}
+
+	bool RendererTask::isCanceled() const
+	{
+		return mState.load() == 3;
+	}
+
+	void RendererTask::wait()
+	{
+		// Task is about to be executed outside of normal rendering workflow. Make sure to manually sync all changes to
+		// the core thread first.
+		// Note: wait() might only get called during serialization, in which case we might call these methods just once
+		// before a level save, instead for every individual component
+		gSceneManager()._updateCoreObjectTransforms();
+		CoreObjectManager::instance().syncToCore();
+
+		auto worker = [this]()
+		{
+			gRenderer()->processTask(*this, true);
+		};
+
+		gCoreThread().queueCommand(worker);
+		gCoreThread().submit(true);
+
+		// Note: Tigger on complete callback and clear it from Renderer?
+	}
+
+	void RendererTask::cancel()
+	{
+		mState.store(3);
+	}
 }}

+ 0 - 2
Source/BansheeEngine/CMakeSources.cmake

@@ -88,7 +88,6 @@ set(BS_BANSHEEENGINE_INC_RENDERER
 	"Include/BsRenderQueue.h"
 	"Include/BsRendererUtility.h"
 	"Include/BsLightProbeCache.h"
-	"Include/BsIBLUtility.h"
 )
 
 set(BS_BANSHEEENGINE_SRC_RTTI
@@ -175,7 +174,6 @@ set(BS_BANSHEEENGINE_SRC_RENDERER
 	"Source/BsRenderQueue.cpp"
 	"Source/BsRendererUtility.cpp"
 	"Source/BsLightProbeCache.cpp"
-	"Source/BsIBLUtility.cpp"
 )
 
 set(BS_BANSHEEENGINE_SRC_INPUT

+ 2 - 0
Source/RenderBeast/CMakeSources.cmake

@@ -18,6 +18,7 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsLightProbes.h"
 	"Include/BsRenderCompositor.h"
 	"Include/BsRendererTextures.h"
+	"Include/BsRenderBeastIBLUtility.h"
 )
 
 set(BS_RENDERBEAST_SRC_NOFILTER
@@ -39,6 +40,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsLightProbes.cpp"
 	"Source/BsRenderCompositor.cpp"
 	"Source/BsRendererTextures.cpp"
+	"Source/BsRenderBeastIBLUtility.cpp"
 )
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 0 - 3
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -78,9 +78,6 @@ namespace bs { namespace ct
 
 		ReflectionProbe* probe;
 		UINT32 arrayIdx;
-		SPtr<Texture> texture;
-		bool customTexture : 1;
-		bool textureDirty : 1;
 		bool arrayDirty : 1;
 		mutable bool errorFlagged : 1;
 	};

+ 5 - 23
Source/RenderBeast/Include/BsRenderBeast.h

@@ -26,12 +26,12 @@ namespace bs
 	/** Contains information global to an entire frame. */
 	struct FrameInfo
 	{
-		FrameInfo(float timeDelta, const RendererAnimationData& animData)
+		FrameInfo(float timeDelta, const RendererAnimationData* animData = nullptr)
 			:timeDelta(timeDelta), animData(animData)
 		{ }
 
 		float timeDelta;
-		const RendererAnimationData& animData;
+		const RendererAnimationData* animData;
 	};
 
 	/**
@@ -69,15 +69,8 @@ namespace bs
 		/** @copydoc Renderer::destroy */
 		void destroy() override;
 
-		/** 
-		 * Captures the scene at the specified location into a cubemap. 
-		 * 
-		 * @param[in]	cubemap		Cubemap to store the results in.
-		 * @param[in]	position	Position to capture the scene at.
-		 * @param[in]	hdr			If true scene will be captured in a format that supports high dynamic range.
-		 * @param[in]	frameInfo	Global information about the the frame currently being rendered.
-		 */
-		void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr, const FrameInfo& frameInfo);
+		/** @copydoc Renderer::captureSceneCubeMap */
+		void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr) override;
 
 	private:
 		/** @copydoc Renderer::notifyCameraAdded */
@@ -111,7 +104,7 @@ namespace bs
 		void notifyReflectionProbeAdded(ReflectionProbe* probe) override;
 
 		/** @copydoc Renderer::notifyReflectionProbeUpdated */
-		void notifyReflectionProbeUpdated(ReflectionProbe* probe) override;
+		void notifyReflectionProbeUpdated(ReflectionProbe* probe, bool texture) override;
 
 		/** @copydoc Renderer::notifyReflectionProbeRemoved */
 		void notifyReflectionProbeRemoved(ReflectionProbe* probe) override;
@@ -172,17 +165,6 @@ namespace bs
 		 */
 		void renderOverlay(RendererView& view);
 
-		/** 
-		 * Renders a single element of a renderable object. 
-		 *
-		 * @param[in]	element		Element to render.
-		 * @param[in]	passIdx		Index of the material pass to render the element with.
-		 * @param[in]	bindPass	If true the material pass will be bound for rendering, if false it is assumed it is
-		 *							already bound.
-		 * @param[in]	viewProj	View projection matrix of the camera the element is being rendered with.
-		 */
-		void renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, const Matrix4& viewProj);
-
 		/**	Creates data used by the renderer on the core thread. */
 		void initializeCore();
 

+ 13 - 46
Source/BansheeEngine/Include/BsIBLUtility.h → Source/RenderBeast/Include/BsRenderBeastIBLUtility.h

@@ -3,6 +3,7 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "BsIBLUtility.h"
 #include "BsRendererMaterial.h"
 #include "BsParamBlocks.h"
 
@@ -220,57 +221,23 @@ namespace bs { namespace ct
 		GpuParamBuffer mInputBuffer;
 	};
 
-	/** Helper class that handles generation and processing of textures used for image based lighting. */
-	class BS_EXPORT IBLUtility
+	/** Render beast implementation of IBLUtility. */
+	class RenderBeastIBLUtility : public IBLUtility
 	{
 	public:
-		/**
-		 * Performs filtering on the cubemap, populating its mip-maps with filtered values that can be used for
-		 * evaluating specular reflections.
-		 * 
-		 * @param[in, out]	cubemap		Cubemap to filter. Its mip level 0 will be read, filtered and written into
-		 *								other mip levels.
-		 * @param[in]		scratch		Temporary cubemap texture to use for the filtering process. Must match the size of
-		 *								the source cubemap. Provide null to automatically create a scratch cubemap.
-		 */
-		static void filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch);
+		/** @copydoc IBLUtility::filterCubemapForSpecular */
+		void filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch) const override;
 
-		/**
-		 * Performs filtering on the cubemap, populating the output cubemap with values that can be used for evaluating
-		 * irradiance for use in diffuse lighting. Uses order-5 SH (25 coefficients) and outputs the values in the form of
-		 * a cubemap.
-		 * 
-		 * @param[in]		cubemap		Cubemap to filter. Its mip level 0 will be used as source.
-		 * @param[in]		output		Output cubemap to store the irradiance data in.
-		 */
-		static void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output);
+		/** @copydoc IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>&, const SPtr<Texture>&) */
+		void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output) const override;
 
-		/**
-		 * Performs filtering on the cubemap, populating the output cubemap with values that can be used for evaluating
-		 * irradiance for use in diffuse lighting. Uses order-5 SH (9 coefficients) and outputs the values in the form of
-		 * a cubemap.
-		 * 
-		 * @param[in]		cubemap		Cubemap to filter. Its mip level 0 will be used as source.
-		 * @param[in]		output		Output buffer in which to place the results. Must be allocated using 
-		 *								IrradianceReduceMat<ORDER>::createOutputBuffer();
-		 * @param[in]		outputIdx	Index in the output buffer at which to write the output coefficients to.
-		 */
-		static void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
-			UINT32 outputIdx);
+		/** @copydoc IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>&, const SPtr<GpuBuffer>&, UINT32) */
+		void filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
+			UINT32 outputIdx) const override;
 
-		/**
-		 * Scales a cubemap and outputs it in the destination texture, using hardware acceleration. If both textures are the
-		 * same size, performs a copy instead.
-		 *
-		 * @param[in]   src				Source cubemap to scale.
-		 * @param[in]   srcMip			Determines which mip level of the source texture to scale.
-		 * @param[in]   dst				Desination texture to output the scaled data to. Must be usable as a render target.
-		 * @param[in]   dstMip			Determines which mip level of the destination texture to scale.
-		 */
-		static void scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip);
+		/** @copydoc IBLUtility::scaleCubemap */
+		void scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip) const override;
 
-		static const UINT32 REFLECTION_CUBEMAP_SIZE;
-		static const UINT32 IRRADIANCE_CUBEMAP_SIZE;
 	private:
 		/** 
 		 * Downsamples a cubemap using hardware bilinear filtering. 
@@ -278,7 +245,7 @@ namespace bs { namespace ct
 		 * @param[in]	src		Cubemap to downsample.
 		 * @param[in]   srcMip	Determines which mip level of the source texture to downsample.
 		 * @param[in]   dst		Desination texture to output the scaled data to. Must be usable as a render target.
-		 * @param[in]   dstMip			Determines which mip level of the destination texture to scale.
+		 * @param[in]   dstMip	Determines which mip level of the destination texture to scale.
 		 */
 		static void downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip);
 	};

+ 1 - 4
Source/RenderBeast/Include/BsRendererScene.h

@@ -105,14 +105,11 @@ namespace bs
 		void registerReflectionProbe(ReflectionProbe* probe);
 
 		/** Updates information about a previously registered reflection probe. */
-		void updateReflectionProbe(ReflectionProbe* probe);
+		void updateReflectionProbe(ReflectionProbe* probe, bool texture);
 
 		/** Removes a reflection probe from the scene. */
 		void unregisterReflectionProbe(ReflectionProbe* probe);
 
-		/** Updates or replaces the filtered reflection texture of the probe at the specified index. */
-		void setReflectionProbeTexture(UINT32 probeIdx, const SPtr<Texture>& texture);
-
 		/** Updates the index at which the reflection probe's texture is stored at, in the global array. */
 		void setReflectionProbeArrayIndex(UINT32 probeIdx, UINT32 arrayIdx, bool markAsClean);
 

+ 0 - 3
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -82,9 +82,6 @@ namespace bs { namespace ct
 		:probe(probe)
 	{
 		arrayIdx = -1;
-		texture = nullptr;
-		customTexture = probe->getCustomTexture() != nullptr;
-		textureDirty = LightProbeCache::instance().isRadianceDirty(probe->getUUID());
 		arrayDirty = true;
 		errorFlagged = false;
 	}

+ 3 - 3
Source/RenderBeast/Source/BsLightProbes.cpp

@@ -4,7 +4,7 @@
 #include "BsLightProbeVolume.h"
 #include "BsGpuBuffer.h"
 #include "BsRendererView.h"
-#include "BsIBLUtility.h"
+#include "BsRenderBeastIBLUtility.h"
 #include "BsRendererManager.h"
 #include "BsRenderBeast.h"
 
@@ -147,9 +147,9 @@ namespace bs { namespace ct
 					SPtr<Texture> cubemap = Texture::create(cubemapDesc);
 
 					RenderBeast& renderer = static_cast<RenderBeast&>(*RendererManager::instance().getActive());
-					renderer.captureSceneCubeMap(cubemap, probePositions[entry.lastUpdatedProbe], true, frameInfo);
+					renderer.captureSceneCubeMap(cubemap, probePositions[entry.lastUpdatedProbe], true);
 
-					IBLUtility::filterCubemapForIrradiance(cubemap, mProbeCoefficientsGPU, probeInfo.bufferIdx);
+					gIBLUtility().filterCubemapForIrradiance(cubemap, mProbeCoefficientsGPU, probeInfo.bufferIdx);
 
 					probeInfo.flags = LightProbeFlags::Clean;
 					numProbeUpdates++;

+ 23 - 62
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -35,6 +35,7 @@
 #include "BsRenderCompositor.h"
 #include "BsMesh.h"
 #include "BsRendererTextures.h"
+#include "BsRenderBeastIBLUtility.h"
 
 using namespace std::placeholders;
 
@@ -70,6 +71,7 @@ namespace bs { namespace ct
 	{
 		RendererUtility::startUp();
 		GpuResourcePool::startUp();
+		IBLUtility::startUp<RenderBeastIBLUtility>();
 		RendererTextures::startUp();
 
 		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>(); 
@@ -103,6 +105,9 @@ namespace bs { namespace ct
 
 	void RenderBeast::destroyCore()
 	{
+		// Make sure all tasks finish first
+		processTasks(true);
+
 		if (mObjectRenderer != nullptr)
 			bs_delete(mObjectRenderer);
 
@@ -115,6 +120,7 @@ namespace bs { namespace ct
 		bs_delete(mMainViewGroup);
 
 		RendererTextures::shutDown();
+		IBLUtility::shutDown();
 		GpuResourcePool::shutDown();
 		RendererUtility::shutDown();
 	}
@@ -175,9 +181,9 @@ namespace bs { namespace ct
 		mScene->registerReflectionProbe(probe);
 	}
 
-	void RenderBeast::notifyReflectionProbeUpdated(ReflectionProbe* probe)
+	void RenderBeast::notifyReflectionProbeUpdated(ReflectionProbe* probe, bool texture)
 	{
-		mScene->updateReflectionProbe(probe);
+		mScene->updateReflectionProbe(probe, texture);
 	}
 
 	void RenderBeast::notifyReflectionProbeRemoved(ReflectionProbe* probe)
@@ -253,7 +259,9 @@ namespace bs { namespace ct
 			gCoreThread().queueCommand(std::bind(&RenderBeast::syncOptions, this, *mOptions));
 			mOptionsDirty = false;
 		}
-
+		
+		// Execute render tasks, after all scene object information has been synced
+		gCoreThread().queueCommand(std::bind(&RenderBeast::processTasks, this, false));
 		gCoreThread().queueCommand(std::bind(&RenderBeast::renderAllCore, this, gTime().getTime(), gTime().getFrameDelta()));
 	}
 
@@ -281,7 +289,7 @@ namespace bs { namespace ct
 		sceneInfo.renderableReady.resize(sceneInfo.renderables.size(), false);
 		sceneInfo.renderableReady.assign(sceneInfo.renderables.size(), false);
 		
-		FrameInfo frameInfo(delta, animData);
+		FrameInfo frameInfo(delta, &animData);
 
 		// Gather all views
 		Vector<RendererView*> views;
@@ -454,23 +462,6 @@ namespace bs { namespace ct
 		gProfilerCPU().endSample("RenderOverlay");
 	}
 	
-	void RenderBeast::renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, 
-									const Matrix4& viewProj)
-	{
-		SPtr<Material> material = element.material;
-
-		if (bindPass)
-			gRendererUtility().setPass(material, passIdx, element.techniqueIdx);
-
-		gRendererUtility().setPassParams(element.params, passIdx);
-
-		if(element.morphVertexDeclaration == nullptr)
-			gRendererUtility().draw(element.mesh, element.subMesh);
-		else
-			gRendererUtility().drawMorph(element.mesh, element.subMesh, element.morphShapeBuffer, 
-				element.morphVertexDeclaration);
-	}
-
 	void RenderBeast::renderReflectionProbes(const FrameInfo& frameInfo)
 	{
 		SceneInfo& sceneInfo = mScene->_getSceneInfo();
@@ -501,18 +492,6 @@ namespace bs { namespace ct
 
 			auto& cubemapArrayProps = sceneInfo.reflProbeCubemapsTex->getProperties();
 
-			TEXTURE_DESC cubemapDesc;
-			cubemapDesc.type = TEX_TYPE_CUBE_MAP;
-			cubemapDesc.format = PF_FLOAT_R11G11B10;
-			cubemapDesc.width = IBLUtility::REFLECTION_CUBEMAP_SIZE;
-			cubemapDesc.height = IBLUtility::REFLECTION_CUBEMAP_SIZE;
-			cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format);
-			cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
-
-			SPtr<Texture> scratchCubemap;
-			if (numProbes > 0)
-				scratchCubemap = Texture::create(cubemapDesc);
-
 			FrameQueue<UINT32> emptySlots;
 			for (UINT32 i = 0; i < numProbes; i++)
 			{
@@ -521,31 +500,13 @@ namespace bs { namespace ct
 				if (probeInfo.arrayIdx > MaxReflectionCubemaps)
 					continue;
 
-				SPtr<Texture> texture = probeInfo.texture;
-				if (texture == nullptr)
-					texture = LightProbeCache::instance().getCachedRadianceTexture(probeInfo.probe->getUUID());
-
-				if (texture == nullptr || probeInfo.textureDirty)
-				{
-					texture = Texture::create(cubemapDesc);
-
-					if (!probeInfo.customTexture)
-						captureSceneCubeMap(texture, probeInfo.probe->getPosition(), true, frameInfo);
-					else
-					{
-						SPtr<Texture> customTexture = probeInfo.probe->getCustomTexture();
-						IBLUtility::scaleCubemap(customTexture, 0, texture, 0);
-					}
-
-					IBLUtility::filterCubemapForSpecular(texture, scratchCubemap);
-					LightProbeCache::instance().setCachedRadianceTexture(probeInfo.probe->getUUID(), texture);
-				}
-
-				mScene->setReflectionProbeTexture(i, texture);
-
 				if(probeInfo.arrayDirty || forceArrayUpdate)
 				{
-					auto& srcProps = probeInfo.texture->getProperties();
+					SPtr<Texture> texture = probeInfo.probe->getFilteredTexture();
+					if (texture == nullptr)
+						continue;
+
+					auto& srcProps = texture->getProperties();
 					bool isValid = srcProps.getWidth() == IBLUtility::REFLECTION_CUBEMAP_SIZE && 
 						srcProps.getHeight() == IBLUtility::REFLECTION_CUBEMAP_SIZE &&
 						srcProps.getNumMipmaps() == cubemapArrayProps.getNumMipmaps() &&
@@ -567,7 +528,7 @@ namespace bs { namespace ct
 					{
 						for(UINT32 face = 0; face < 6; face++)
 							for(UINT32 mip = 0; mip <= srcProps.getNumMipmaps(); mip++)
-								probeInfo.texture->copy(sceneInfo.reflProbeCubemapsTex, face, mip, probeInfo.arrayIdx * 6 + face, mip);
+								texture->copy(sceneInfo.reflProbeCubemapsTex, face, mip, probeInfo.arrayIdx * 6 + face, mip);
 					}
 
 					mScene->setReflectionProbeArrayIndex(i, probeInfo.arrayIdx, true);
@@ -603,8 +564,8 @@ namespace bs { namespace ct
 
 					sky.filteredReflections = Texture::create(cubemapDesc);
 
-					IBLUtility::scaleCubemap(sky.radiance, 0, sky.filteredReflections, 0);
-					IBLUtility::filterCubemapForSpecular(sky.filteredReflections, nullptr);
+					gIBLUtility().scaleCubemap(sky.radiance, 0, sky.filteredReflections, 0);
+					gIBLUtility().filterCubemapForSpecular(sky.filteredReflections, nullptr);
 					LightProbeCache::instance().setCachedRadianceTexture(sky.skybox->getUUID(), sky.filteredReflections);
 				}
 			}
@@ -625,7 +586,7 @@ namespace bs { namespace ct
 
 					sky.irradiance = Texture::create(irradianceCubemapDesc);
 
-					IBLUtility::filterCubemapForIrradiance(sky.filteredReflections, sky.irradiance);
+					gIBLUtility().filterCubemapForIrradiance(sky.filteredReflections, sky.irradiance);
 					LightProbeCache::instance().setCachedIrradianceTexture(sky.skybox->getUUID(), sky.filteredReflections);
 				}
 			}
@@ -637,7 +598,7 @@ namespace bs { namespace ct
 		}
 	}
 
-	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr, const FrameInfo& frameInfo)
+	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr)
 	{
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		auto& texProps = cubemap->getProperties();
@@ -751,7 +712,7 @@ namespace bs { namespace ct
 		RendererViewGroup viewGroup(viewPtrs, 6, mCoreOptions->shadowMapSize);
 		viewGroup.determineVisibility(sceneInfo);
 
+		FrameInfo frameInfo(1.0f/60.0f);
 		renderViews(viewGroup, frameInfo);
 	}
-
 }}

+ 9 - 10
Source/BansheeEngine/Source/BsIBLUtility.cpp → Source/RenderBeast/Source/BsRenderBeastIBLUtility.cpp

@@ -1,6 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsIBLUtility.h"
+#include "BsRenderBeastIBLUtility.h"
 #include "BsTexture.h"
 #include "BsGpuParamsSet.h"
 #include "BsRendererUtility.h"
@@ -277,10 +277,7 @@ namespace bs { namespace ct
 		gRendererUtility().drawScreenQuad();
 	}
 
-	const UINT32 IBLUtility::REFLECTION_CUBEMAP_SIZE = 256;
-	const UINT32 IBLUtility::IRRADIANCE_CUBEMAP_SIZE = 32;
-
-	void IBLUtility::filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch)
+	void RenderBeastIBLUtility::filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch) const
 	{
 		auto& props = cubemap->getProperties();
 
@@ -342,7 +339,7 @@ namespace bs { namespace ct
 		rapi.setRenderTarget(nullptr);
 	}
 
-	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output)
+	void RenderBeastIBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output) const
 	{
 		IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(5);
 		IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(5);
@@ -369,8 +366,8 @@ namespace bs { namespace ct
 		}
 	}
 
-	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
-		UINT32 outputIdx)
+	void RenderBeastIBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
+		UINT32 outputIdx) const
 	{
 		IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(3);
 		IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(3);
@@ -383,7 +380,8 @@ namespace bs { namespace ct
 		shReduce->execute(coeffSetBuffer, numCoeffSets, output, outputIdx);
 	}
 
-	void IBLUtility::scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip)
+	void RenderBeastIBLUtility::scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, 
+		UINT32 dstMip) const
 	{
 		auto& srcProps = src->getProperties();
 		auto& dstProps = dst->getProperties();
@@ -428,7 +426,8 @@ namespace bs { namespace ct
 			downsampleCubemap(scratchTex, srcMip, dst, dstMip);
 	}
 
-	void IBLUtility::downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip)
+	void RenderBeastIBLUtility::downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, 
+		UINT32 dstMip)
 	{
 		for (UINT32 face = 0; face < 6; face++)
 		{

+ 8 - 14
Source/RenderBeast/Source/BsRendererScene.cpp

@@ -424,17 +424,17 @@ namespace bs {	namespace ct
 		}
 	}
 
-	void RendererScene::updateReflectionProbe(ReflectionProbe* probe)
+	void RendererScene::updateReflectionProbe(ReflectionProbe* probe, bool texture)
 	{
 		// Should only get called if transform changes, any other mInfo.ajor changes and ReflProbeInfo entry gets rebuild
 		UINT32 probeId = probe->getRendererId();
 		mInfo.reflProbeWorldBounds[probeId] = probe->getBounds();
 
-		RendererReflectionProbe& probeInfo = mInfo.reflProbes[probeId];
-		probeInfo.arrayDirty = true;
-
-		LightProbeCache::instance().notifyDirty(probe->getUUID());
-		probeInfo.textureDirty = true;
+		if (texture)
+		{
+			RendererReflectionProbe& probeInfo = mInfo.reflProbes[probeId];
+			probeInfo.arrayDirty = true;
+		}
 	}
 
 	void RendererScene::unregisterReflectionProbe(ReflectionProbe* probe)
@@ -464,13 +464,6 @@ namespace bs {	namespace ct
 		LightProbeCache::instance().unloadCachedTexture(probe->getUUID());
 	}
 
-	void RendererScene::setReflectionProbeTexture(UINT32 probeIdx, const SPtr<Texture>& texture)
-	{
-		RendererReflectionProbe* probe = &mInfo.reflProbes[probeIdx];
-		probe->texture = texture;
-		probe->textureDirty = false;
-	}
-
 	void RendererScene::setReflectionProbeArrayIndex(UINT32 probeIdx, UINT32 arrayIdx, bool markAsClean)
 	{
 		RendererReflectionProbe* probe = &mInfo.reflProbes[probeIdx];
@@ -752,7 +745,8 @@ namespace bs {	namespace ct
 			return;
 		
 		// Note: Before uploading bone matrices perhaps check if they has actually been changed since last frame
-		mInfo.renderables[idx]->renderable->updateAnimationBuffers(frameInfo.animData);
+		if(frameInfo.animData != nullptr)
+			mInfo.renderables[idx]->renderable->updateAnimationBuffers(*frameInfo.animData);
 		
 		// Note: Could this step be moved in notifyRenderableUpdated, so it only triggers when material actually gets
 		// changed? Although it shouldn't matter much because if the internal versions keeping track of dirty params.