Browse Source

Individual core object syncing with dependencies
Added optional dependency checking for resource handle isLoaded method
Remove automatic syncing from core to sim thread

Marko Pintera 11 years ago
parent
commit
550b861440
42 changed files with 469 additions and 534 deletions
  1. 1 10
      BansheeCore/Include/BsCoreObject.h
  2. 0 32
      BansheeCore/Include/BsCoreObjectCore.h
  3. 16 59
      BansheeCore/Include/BsCoreObjectManager.h
  4. 5 0
      BansheeCore/Include/BsFont.h
  5. 2 2
      BansheeCore/Include/BsMaterial.h
  6. 0 10
      BansheeCore/Include/BsMeshBase.h
  7. 0 10
      BansheeCore/Include/BsMultiRenderTexture.h
  8. 0 5
      BansheeCore/Include/BsRenderTarget.h
  9. 0 10
      BansheeCore/Include/BsRenderTexture.h
  10. 20 13
      BansheeCore/Include/BsRenderWindow.h
  11. 42 20
      BansheeCore/Include/BsRenderWindowManager.h
  12. 6 0
      BansheeCore/Include/BsResource.h
  13. 4 1
      BansheeCore/Include/BsResourceHandle.h
  14. 5 0
      BansheeCore/Include/BsShader.h
  15. 0 25
      BansheeCore/Include/Win32/BsPlatformImpl.h
  16. 2 15
      BansheeCore/Source/BsCoreApplication.cpp
  17. 44 20
      BansheeCore/Source/BsCoreObject.cpp
  18. 1 1
      BansheeCore/Source/BsCoreObjectCore.cpp
  19. 38 95
      BansheeCore/Source/BsCoreObjectManager.cpp
  20. 14 0
      BansheeCore/Source/BsFont.cpp
  21. 3 52
      BansheeCore/Source/BsMaterial.cpp
  22. 2 1
      BansheeCore/Source/BsMesh.cpp
  23. 0 14
      BansheeCore/Source/BsMeshBase.cpp
  24. 0 17
      BansheeCore/Source/BsMultiRenderTexture.cpp
  25. 1 0
      BansheeCore/Source/BsRenderAPI.cpp
  26. 0 9
      BansheeCore/Source/BsRenderTarget.cpp
  27. 0 17
      BansheeCore/Source/BsRenderTexture.cpp
  28. 9 22
      BansheeCore/Source/BsRenderWindow.cpp
  29. 76 9
      BansheeCore/Source/BsRenderWindowManager.cpp
  30. 7 2
      BansheeCore/Source/BsResourceHandle.cpp
  31. 52 0
      BansheeCore/Source/BsShader.cpp
  32. 0 21
      BansheeCore/Source/Win32/BsPlatformImpl.cpp
  33. 2 5
      BansheeCore/Source/Win32/BsPlatformWndProc.cpp
  34. 10 0
      BansheeD3D11RenderSystem/Include/BsD3D11RenderWindow.h
  35. 22 7
      BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp
  36. 10 0
      BansheeD3D9RenderSystem/Include/BsD3D9RenderWindow.h
  37. 20 8
      BansheeD3D9RenderSystem/Source/BsD3D9RenderWindow.cpp
  38. 5 0
      BansheeEngine/Include/BsSpriteTexture.h
  39. 5 0
      BansheeEngine/Source/BsSpriteTexture.cpp
  40. 11 1
      BansheeGLRenderSystem/Include/BsWin32Window.h
  41. 21 9
      BansheeGLRenderSystem/Source/BsWin32Window.cpp
  42. 13 12
      TODO.txt

+ 1 - 10
BansheeCore/Include/BsCoreObject.h

@@ -189,7 +189,7 @@ namespace BansheeEngine
 		 *			method to trigger the next time objects are synced between core and sim threads.
 		 *
 		 * @param	flags	Optional flags in case you want to signal that only part of the
-		 *					internal data is dirty. syncFromCore() will be called regardless
+		 *					internal data is dirty. syncToCore() will be called regardless
 		 *					and it's up to the implementation to read the flags value if needed.
 		 */
 		void markCoreDirty(UINT32 flags = 0xFFFFFFFF) { mCoreDirtyFlags |= flags; }
@@ -221,15 +221,6 @@ namespace BansheeEngine
 		 */
 		virtual CoreSyncData syncToCore(FrameAlloc* allocator) { return CoreSyncData(); }
 
-		/**
-		 * @brief	Update internal data from provided memory buffer that
-		 *			was populated with data from the core thread.
-		 *
-		 * @note	This generally happens at the start of every sim thread frame. Provided data
-		 *			is from a previous core thread frame.
-		 */
-		virtual void syncFromCore(const CoreSyncData& data) { }
-
 		/**
 		 * @brief	Populates the provided array with all core objects that this core object depends upon.
 		 */

+ 0 - 32
BansheeCore/Include/BsCoreObjectCore.h

@@ -51,15 +51,6 @@ namespace BansheeEngine
 		friend class CoreObjectManager;
 		friend class CoreObject;
 
-		/**
-		 * @brief	Copy internal dirty data to a memory buffer that will be used
-		 *			for updating sim thread version of that data.
-		 *
-		 * @note	This generally happens at the end of a core thread frame. Data is then passed
-		 *			to the sim thread and will be available on the next sim thread frame.
-		 */
-		virtual CoreSyncData syncFromCore(FrameAlloc* allocator) { return CoreSyncData(); }
-
 		/**
 		 * @brief	Update internal data from provided memory buffer that
 		 *			was populated with data from the sim thread.
@@ -69,28 +60,6 @@ namespace BansheeEngine
 		 */
 		virtual void syncToCore(const CoreSyncData& data) { }
 
-		/**
-		 * @brief	Marks the core data as dirty. This causes the syncFromCore()
-		 *			method to trigger the next time objects are synced between core and sim threads.
-		 *
-		 * @param	flags	Optional flags in case you want to signal that only part of the
-		 *					internal data is dirty. syncFromCore() will be called regardless
-		 *					and it's up to the implementation to read the flags value if needed.
-		 */
-		void markCoreDirty(UINT32 flags = 0xFFFFFFFF) { mCoreDirtyFlags |= flags; }
-
-		/**
-		 * @brief	Marks the core data as clean. Normally called right after syncFromCore()
-		 *			has been called.
-		 */
-		void markCoreClean() { mCoreDirtyFlags = 0; }
-
-		/**
-		 * @brief	Checks is the core dirty flag set. This is used by external systems 
-		 *			to know when internal data has changed and sim thread potentially needs to be notified.
-		 */
-		bool isCoreDirty() const { return mCoreDirtyFlags != 0; }
-
 		/**
 		 * @brief	Blocks the current thread until the resource is fully initialized.
 		 * 			
@@ -109,7 +78,6 @@ namespace BansheeEngine
 		void setIsInitialized(bool initialized) { mFlags = initialized ? mFlags | CGCO_INITIALIZED : mFlags & ~CGCO_INITIALIZED; }
 		void setScheduledToBeInitialized(bool scheduled) { mFlags = scheduled ? mFlags | CGCO_SCHEDULED_FOR_INIT : mFlags & ~CGCO_SCHEDULED_FOR_INIT; }
 
-		UINT32 mCoreDirtyFlags;
 		volatile UINT8 mFlags;
 		std::weak_ptr<CoreObjectCore> mThis;
 

+ 16 - 59
BansheeCore/Include/BsCoreObjectManager.h

@@ -9,16 +9,6 @@ namespace BansheeEngine
 	// TODO Low priority - Add debug option that would remember a call stack for each resource initialization,
 	// so when we fail to release one we know which one it is.
 	
-	/**
-	 * @brief	Determines type of synchronization to perform when syncing
-	 *			dirty data between core and sim threads.
-	 */
-	enum CoreObjectSync
-	{
-		Sim, /** Syncing sim thread data to core thread. */
-		Core /** Syncing core thread data to sim thread. */
-	};
-
 	/**
 	 * @brief	Manager that keeps track of all active CoreObjects.
 	 * 			
@@ -26,24 +16,6 @@ namespace BansheeEngine
 	 */
 	class BS_CORE_EXPORT CoreObjectManager : public Module<CoreObjectManager>
 	{
-		/**
-		 * @brief	Stores dirty data that is to be transferred from core 
-		 *			thread to sim thread part of a CoreObject, for a single object.
-		 */
-		struct SimStoredSyncObjData
-		{
-			SimStoredSyncObjData()
-				:destinationObj(nullptr)
-			{ }
-
-			SimStoredSyncObjData(CoreObject* destObj, const CoreSyncData& syncData)
-				:destinationObj(destObj), syncData(syncData)
-			{ }
-
-			CoreObject* destinationObj;
-			CoreSyncData syncData;
-		};
-
 		/**
 		 * @brief	Stores dirty data that is to be transferred from sim 
 		 *			thread to core thread part of a CoreObject, for a single object.
@@ -62,17 +34,6 @@ namespace BansheeEngine
 			CoreSyncData syncData;
 		};
 
-		/**
-		 * @brief	Stores dirty data that is to be transferred from core 
-		 *			thread to sim thread part of a CoreObject, for all dirty 
-		 *			objects in one frame.
-		 */
-		struct SimStoredSyncData
-		{
-			FrameAlloc* alloc = nullptr;
-			Map<UINT64, SimStoredSyncObjData> entries;
-		};
-
 		/**
 		 * @brief	Stores dirty data that is to be transferred from sim 
 		 *			thread to core thread part of a CoreObject, for all dirty
@@ -100,44 +61,40 @@ namespace BansheeEngine
 		 */
 		void unregisterObject(CoreObject* object);
 
+		/**
+		 * @brief	Synchronizes all dirty CoreObjects with the core thread. Their dirty data will be
+		 *			allocated using the provided allocator and then queued for update using the provided
+		 *			core thread accessor.
+		 *
+		 * @note	Sim thread only.
+		 */
+		void syncToCore(CoreAccessor& accessor);
+
+	private:
 		/**
 		 * @brief	Stores all syncable data from dirty core objects into memory allocated
 		 *			by the provided allocator. Additional meta-data is stored internally to be
 		 *			used by call to syncUpload.
 		 *
-		 * @param	type	Determines where to copy the dirty data from. If set to Sim the data copied
-		 *					will be data accessible by the sim thread, and if set to Core the data copied
-		 *					will be data accessible by the core thread.
 		 * @param	allocator Allocator to use for allocating memory for stored data.
 		 *
-		 * @note	Not thread safe. If used with Sim type it should only be called from
-		 *			sim thread, and if used with Core type it should only be called from
-		 *			core thread.
-		 *
+		 * @note	Sim thread only.
 		 *			Must be followed by a call to syncUpload with the same type.
 		 */
-		void syncDownload(CoreObjectSync type, FrameAlloc* allocator);
+		void syncDownload(FrameAlloc* allocator);
 
 		/**
 		 * @brief	Copies all the data stored by previous call to "syncDownload"
-		 *			into CoreObjects or their core thread versions.
+		 *			into core thread versions of CoreObjects.
 		 *
-		 * @param	type	Determines where to copy the stored data to. This will be the opposite 
-		 *					data source than used by "syncDownload". If set to Sim the data will be
-		 *					copied to data accessible by core thread, and if set to Core the data 
-		 *					will be copied to data accessible by the sim thread. 
-		 *
-		 * @note	Not thread safe. If used with Sim type it should only be called from
-		 *			core thread, and if used with Core type it should only be called from
-		 *			sim thread.
+		 * @note	Core thread only.
+		 *			Must be preceded by a call to syncDownload.
 		 */
-		void syncUpload(CoreObjectSync type);
+		void syncUpload();
 
-	private:
 		UINT64 mNextAvailableID;
 		Map<UINT64, CoreObject*> mObjects;
 
-		List<SimStoredSyncData> mSimSyncData;
 		List<CoreStoredSyncData> mCoreSyncData;
 
 		BS_MUTEX(mObjectsMutex);

+ 5 - 0
BansheeCore/Include/BsFont.h

@@ -84,6 +84,11 @@ namespace BansheeEngine
 
 		Font();
 
+		/**
+		 * @copydoc	Resource::areDependenciesLoaded
+		 */
+		bool areDependenciesLoaded() const;
+
 		/**
 		 * @copydoc	CoreObject::getCoreDependencies
 		 */

+ 2 - 2
BansheeCore/Include/BsMaterial.h

@@ -691,9 +691,9 @@ namespace BansheeEngine
 		void notifyResourceChanged(const HResource& resource);
 
 		/**
-		 * @brief	Checks if all resources needed for initialization have been loaded.
+		 * @copydoc	Resource::areDependenciesLoaded
 		 */
-		bool checkIfDependenciesLoaded() const;
+		bool areDependenciesLoaded() const;
 
 		/**
 		 * @brief	Performs material initialization when all resources are ready.

+ 0 - 10
BansheeCore/Include/BsMeshBase.h

@@ -138,11 +138,6 @@ namespace BansheeEngine
 		const MeshProperties& getProperties() const { return mProperties; }
 
 	protected:
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual CoreSyncData syncFromCore(FrameAlloc* allocator);
-
 		/**
 		 * @copydoc	CoreObjectCore::syncToCore
 		 */
@@ -200,11 +195,6 @@ namespace BansheeEngine
 		 */
 		virtual CoreSyncData syncToCore(FrameAlloc* allocator);
 
-		/**
-		 * @copydoc	CoreObject::syncFromCore
-		 */
-		virtual void syncFromCore(const CoreSyncData& data);
-
 		MeshProperties mProperties;
 
 		/************************************************************************/

+ 0 - 10
BansheeCore/Include/BsMultiRenderTexture.h

@@ -68,11 +68,6 @@ namespace BansheeEngine
 	protected:
 		MultiRenderTextureCore(const MULTI_RENDER_TEXTURE_CORE_DESC& desc);
 
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual CoreSyncData syncFromCore(FrameAlloc* allocator);
-
 		/**
 		 * @copydoc	CoreObjectCore::syncToCore
 		 */
@@ -154,11 +149,6 @@ namespace BansheeEngine
 		 */
 		virtual CoreSyncData syncToCore(FrameAlloc* allocator);
 
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual void syncFromCore(const CoreSyncData& data);
-
 		MULTI_RENDER_TEXTURE_DESC mDesc;
 		Vector<HTexture> mBindableColorTex;
 		HTexture mBindableDepthStencilTex;

+ 0 - 5
BansheeCore/Include/BsRenderTarget.h

@@ -145,11 +145,6 @@ namespace BansheeEngine
 		RenderTargetCore();
 		virtual ~RenderTargetCore() { }
 
-		/**
-		 * @brief	Makes the render target active or inactive. (e.g. for a window, it will hide or restore the window).
-		 */
-		virtual void setActive(bool state);
-
 		/**
 		 * @brief	Sets a priority that determines in which orders the render targets the processed.
 		 * 			

+ 0 - 10
BansheeCore/Include/BsRenderTexture.h

@@ -80,11 +80,6 @@ namespace BansheeEngine
 		const RenderTextureProperties& getProperties() const;
 
 	protected:
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual CoreSyncData syncFromCore(FrameAlloc* allocator);
-
 		/**
 		 * @copydoc	CoreObjectCore::syncToCore
 		 */
@@ -180,11 +175,6 @@ namespace BansheeEngine
 		 */
 		virtual CoreSyncData syncToCore(FrameAlloc* allocator);
 
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual void syncFromCore(const CoreSyncData& data);
-
 	protected:
 		HTexture mBindableColorTex;
 		HTexture mBindableDepthStencilTex;

+ 20 - 13
BansheeCore/Include/BsRenderWindow.h

@@ -146,6 +146,11 @@ namespace BansheeEngine
          */
         virtual void setHidden(bool hidden);
 
+		/**
+		 * @brief	Makes the render target active or inactive. (e.g. for a window, it will hide or restore the window).
+		 */
+		virtual void setActive(bool state);
+
         /**
          * @brief	Change the size of the window.
          */
@@ -168,10 +173,6 @@ namespace BansheeEngine
 		 */
 		virtual void _windowMovedOrResized();
 
-	protected:
-		friend class RenderWindow;
-		friend class RenderWindowManager;
-
 		/**
 		 * @brief	Called when window has received focus.
 		 *
@@ -186,16 +187,21 @@ namespace BansheeEngine
 		 */
 		virtual void _windowFocusLost();
 
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual CoreSyncData syncFromCore(FrameAlloc* allocator);
+	protected:
+		friend class RenderWindow;
+		friend class RenderWindowManager;
 
 		/**
 		 * @copydoc	CoreObjectCore::syncToCore
 		 */
 		virtual void syncToCore(const CoreSyncData& data);
 
+		/**
+		 * @brief	Retrieves data that is to be used for syncing between core and sim thread
+		 *			versions of this object.
+		 */
+		virtual UINT32 getSyncData(UINT8* buffer) { return 0; }
+
 		RENDER_WINDOW_DESC mDesc;
 	};
 
@@ -283,6 +289,12 @@ namespace BansheeEngine
 
 		RenderWindow(const RENDER_WINDOW_DESC& desc);
 
+		/**
+		 * @brief	Updates internal properties using the provided data. Data must have been retrieved from
+		 *			"getSyncData" method of the core version of this object.
+		 */
+		virtual void setSyncData(UINT8* buffer, UINT32 size) { }
+
 		/**
 		 * @copydoc	RenderTarget::createCore
 		 */
@@ -293,11 +305,6 @@ namespace BansheeEngine
 		 */
 		virtual CoreSyncData syncToCore(FrameAlloc* allocator);
 
-		/**
-		 * @copydoc	CoreObjectCore::syncFromCore
-		 */
-		virtual void syncFromCore(const CoreSyncData& data);
-
 	protected:
 		RENDER_WINDOW_DESC mDesc;
     };

+ 42 - 20
BansheeCore/Include/BsRenderWindowManager.h

@@ -10,12 +10,23 @@ namespace BansheeEngine
 	/**
 	 * @brief	Handles creation and internal updates relating to render windows.
 	 *
-	 * @note	Sim thread only.
+	 * @note	Internal class.
 	 */
 	class BS_CORE_EXPORT RenderWindowManager : public Module<RenderWindowManager>
 	{
+		/**
+		 * @brief	Holds a buffer that contains dirty data used for updating sim
+		 *			thread render windows after changes on the core thread.
+		 */
+		struct DirtyPropertyData
+		{
+			UINT8* data;
+			UINT32 size;
+		};
+
 	public:
 		RenderWindowManager();
+		~RenderWindowManager();
 
 		/**
 		 * @brief	Creates a new render window using the specified options. Optionally
@@ -30,6 +41,31 @@ namespace BansheeEngine
 		 */
 		void _update();
 
+		/**
+		 * @brief	Called by the core thread when window is destroyed.
+		 */
+		void notifyWindowDestroyed(RenderWindow* window);
+
+		/**
+		 * @brief	Called by the core thread when window receives focus.
+		 */
+		void notifyFocusReceived(RenderWindowCore* window);
+
+		/**
+		 * @brief	Called by the core thread when window loses focus.
+		 */
+		void notifyFocusLost(RenderWindowCore* window);
+
+		/**
+		 * @brief	Called by the core thread when window is moved or resized.
+		 */
+		void notifyMovedOrResized(RenderWindowCore* window);
+
+		/**
+		 * @brief	Called by the core thread when window properties change.
+		 */
+		void notifyPropertiesDirty(RenderWindowCore* window);
+
 		/**
 		 * @brief	Returns a list of all open render windows.
 		 */
@@ -52,35 +88,20 @@ namespace BansheeEngine
 	protected:
 		friend class RenderWindow;
 
-		/**
-		 * @brief	Called by the core thread when window is destroyed.
-		 */
-		void windowDestroyed(RenderWindow* window);
-
-		/**
-		 * @brief	Called by the core thread when window receives focus.
-		 */
-		void windowFocusReceived(RenderWindowCore* window);
-
-		/**
-		 * @brief	Called by the core thread when window loses focus.
-		 */
-		void windowFocusLost(RenderWindowCore* window);
-
 		/**
 		 * @brief	Called by the core thread when mouse leaves a window.
 		 */
 		void windowMouseLeft(RenderWindowCore* window);
 
 		/**
-		 * @brief	Called by the sim thread when window is moved or resized.
+		 * @brief	Finds a sim thread equivalent of the provided core thread window implementation.
 		 */
-		void windowMovedOrResized(RenderWindow* window);
+		RenderWindow* getNonCore(const RenderWindowCore* window) const;
 
 		/**
-		 * @brief	Finds a sim thread equivalent of the provided core thread window implementation.
+		 * @brief	Adds a new dirty property entry.
 		 */
-		RenderWindow* getNonCore(const RenderWindowCore* window) const;
+		void setDirtyProperties(RenderWindowCore* coreWindow);
 
 		/**
 		 * @copydoc	create
@@ -96,6 +117,7 @@ namespace BansheeEngine
 		RenderWindow* mNewWindowInFocus;
 		Vector<RenderWindow*> mMovedOrResizedWindows;
 		Vector<RenderWindow*> mMouseLeftWindows;
+		Map<RenderWindow*, DirtyPropertyData> mDirtyProperties;
 	};
 
 	/**

+ 6 - 0
BansheeCore/Include/BsResource.h

@@ -37,6 +37,12 @@ namespace BansheeEngine
 
 	protected:
 		friend class Resources;
+		friend class ResourceHandleBase;
+
+		/**
+		 * @brief	Checks if are all resources that this resource depends on loaded.
+		 */
+		virtual bool areDependenciesLoaded() const { return true; }
 
 		UINT32 mSize;
 		ResourceMetaDataPtr mMetaData;

+ 4 - 1
BansheeCore/Include/BsResourceHandle.h

@@ -32,8 +32,11 @@ namespace BansheeEngine
 		/**
 		 * @brief	Checks if the resource is loaded. Until resource is loaded this handle
 		 *			is invalid and you may not get the internal resource from it.
+		 *
+		 * @param	checkDependencies	If true, and if resource has any dependencies, this method will
+		 *								also check if they are loaded.
 		 */
-		bool isLoaded() const;
+		bool isLoaded(bool checkDependencies = true) const;
 
 		/**
 		 * @brief	Blocks the current thread until the resource is fully loaded.

+ 5 - 0
BansheeCore/Include/BsShader.h

@@ -309,6 +309,11 @@ namespace BansheeEngine
 	private:
 		Shader(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques);
 
+		/**
+		 * @copydoc	Resource::areDependenciesLoaded
+		 */
+		bool areDependenciesLoaded() const;
+
 		/**
 		 * @copydoc	CoreObject::getCoreDependencies
 		 */

+ 0 - 25
BansheeCore/Include/Win32/BsPlatformImpl.h

@@ -321,27 +321,6 @@ namespace BansheeEngine
 		 */
 		static Event<void(UINT32)> onCharInput;
 
-		/**
-		 * @brief	Triggered whenever a window receives focus.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(RenderWindowCore*)> onWindowFocusReceived;
-
-		/**
-		 * @brief	Triggered whenever a window loses focus.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(RenderWindowCore*)> onWindowFocusLost;
-
-		/**
-		 * @brief	Triggered whenever a window gets moved or resized.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(RenderWindowCore*)> onWindowMovedOrResized;
-
 		/**
 		 * @brief	Triggered whenever mouse capture state for the window is changed
 		 * 			(it receives or loses it).
@@ -367,9 +346,5 @@ namespace BansheeEngine
 
 		static void win32ShowCursor();
 		static void win32HideCursor();
-
-		static void windowFocusReceived(RenderWindowCore* window);
-		static void windowFocusLost(RenderWindowCore* window);
-		static void windowMovedOrResized(RenderWindowCore* window);
 	};
 }

+ 2 - 15
BansheeCore/Source/BsCoreApplication.cpp

@@ -196,8 +196,7 @@ namespace BansheeEngine
 			ResourceListenerManager::instance().update();
 
 			// Sync all dirty sim thread CoreObject data to core thread
-			CoreObjectManager::instance().syncDownload(CoreObjectSync::Sim, gCoreThread().getFrameAlloc());
-			gCoreAccessor().queueCommand(std::bind(&CoreObjectManager::syncUpload, CoreObjectManager::instancePtr(), CoreObjectSync::Sim));
+			CoreObjectManager::instance().syncToCore(gCoreAccessor());
 
 			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
 
@@ -218,20 +217,11 @@ namespace BansheeEngine
 				mIsFrameRenderingFinished = false;
 			}
 
-			// Sync all dirty core thread CoreObject data to sim thread
-			// Note: This relies on core thread having finished the frame (ensured by the sync primitive above)
-			CoreObjectManager::instance().syncUpload(CoreObjectSync::Core);
-
 			gCoreThread().queueCommand(&Platform::_coreUpdate);
 
-			FrameAlloc* coreFrameAlloc = gCoreThread().getFrameAlloc();
-			gCoreThread().update(); // Active frame allocator now belongs to core thread, do not use it on sim thread anymore
+			gCoreThread().update(); 
 			gCoreThread().submitAccessors(); 
 
-			// This should be called after accessors are submitted to ensure we don't sync CoreObjects that are 
-			// about to be destroyed (They're only ever destroyed from accessors)
-			gCoreThread().queueCommand(std::bind(&CoreObjectManager::syncDownload, CoreObjectManager::instancePtr(), 
-				CoreObjectSync::Core, coreFrameAlloc));
 			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
 			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
 
@@ -250,9 +240,6 @@ namespace BansheeEngine
 				TaskScheduler::instance().removeWorker();
 			}
 		}
-
-		// One final sync in order to dealloc anything that was queued for sync from core
-		CoreObjectManager::instance().syncUpload(CoreObjectSync::Core);
 	}
 
 	void CoreApplication::update()

+ 44 - 20
BansheeCore/Source/BsCoreObject.cpp

@@ -80,13 +80,6 @@ namespace BansheeEngine
 
 	void CoreObject::syncToCore(CoreAccessor& accessor)
 	{
-		if (!isCoreDirty())
-			return;
-
-		SPtr<CoreObjectCore> destObj = getCore();
-		if (destObj == nullptr)
-			return;
-
 		struct IndividualCoreSyncData
 		{
 			SPtr<CoreObjectCore> destination;
@@ -94,25 +87,56 @@ namespace BansheeEngine
 			FrameAlloc* allocator;
 		};
 
-		IndividualCoreSyncData data;
-		data.allocator = gCoreThread().getFrameAlloc();
-		data.destination = destObj;
-		data.syncData = syncToCore(data.allocator);
+		FrameAlloc* allocator = gCoreThread().getFrameAlloc();
+
+		Vector<SPtr<CoreObject>> dependencies;
+		Vector<IndividualCoreSyncData> syncData;
 
-		std::function<void(const IndividualCoreSyncData&)> callback =
-			[](const IndividualCoreSyncData& data)
+		UINT32 stackPos = 0;
+
+		dependencies.push_back(getThisPtr());
+		while (stackPos < dependencies.size())
 		{
-			data.destination->syncToCore(data.syncData);
+			SPtr<CoreObject> curObj = dependencies[stackPos];
+			stackPos++;
 
-			UINT8* dataPtr = data.syncData.getBuffer();
+			if (curObj->isCoreDirty())
+			{
+				SPtr<CoreObjectCore> destObj = curObj->getCore();
+				if (destObj == nullptr)
+					return;
 
-			if (dataPtr != nullptr)
-				data.allocator->dealloc(dataPtr);
-		};
+				IndividualCoreSyncData data;
+				data.allocator = allocator;
+				data.destination = destObj;
+				data.syncData = syncToCore(data.allocator);
+
+				syncData.push_back(data);
+
+				curObj->markCoreClean();
+			}
 
-		accessor.queueCommand(std::bind(callback, data));
+			// Note: I don't check for recursion. Possible infinite loop if two objects
+			// are dependent on one another.
+			curObj->getCoreDependencies(dependencies);
+		}
+
+		std::function<void(const Vector<IndividualCoreSyncData>&)> callback =
+			[](const Vector<IndividualCoreSyncData>& data)
+		{
+			for (auto& entry : data)
+			{
+				entry.destination->syncToCore(entry.syncData);
+
+				UINT8* dataPtr = entry.syncData.getBuffer();
+
+				if (dataPtr != nullptr)
+					entry.allocator->dealloc(dataPtr);
+			}
+		};
 
-		markCoreClean();
+		if (syncData.size() > 0)
+			accessor.queueCommand(std::bind(callback, syncData));
 	}
 
 	void CoreObject::_setThisPtr(std::shared_ptr<CoreObject> ptrThis)

+ 1 - 1
BansheeCore/Source/BsCoreObjectCore.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 		BS_STATIC_MUTEX_CLASS_INSTANCE(mCoreGpuObjectLoadedMutex, CoreObjectCore)
 
 	CoreObjectCore::CoreObjectCore()
-		:mCoreDirtyFlags(0xFFFFFFFF), mFlags(0)
+		:mFlags(0)
 	{ }
 
 	CoreObjectCore::~CoreObjectCore()

+ 38 - 95
BansheeCore/Source/BsCoreObjectManager.cpp

@@ -4,6 +4,7 @@
 #include "BsException.h"
 #include "BsMath.h"
 #include "BsFrameAlloc.h"
+#include "BsCoreThread.h"
 
 namespace BansheeEngine
 {
@@ -50,128 +51,70 @@ namespace BansheeEngine
 		UINT64 internalId = object->getInternalID();
 		mObjects.erase(internalId);
 
+		for (auto& syncData : mCoreSyncData)
 		{
-			for (auto& syncData : mSimSyncData)
+			auto iterFind = syncData.entries.find(internalId);
+			if (iterFind != syncData.entries.end())
 			{
-				auto iterFind = syncData.entries.find(internalId);
-				if (iterFind != syncData.entries.end())
-				{
-					UINT8* data = iterFind->second.syncData.getBuffer();
+				UINT8* data = iterFind->second.syncData.getBuffer();
 
-					if (data != nullptr && syncData.alloc != nullptr)
-						syncData.alloc->dealloc(data);
+				if (data != nullptr && syncData.alloc != nullptr)
+					syncData.alloc->dealloc(data);
 
-					syncData.entries.erase(iterFind);
-				}
+				syncData.entries.erase(iterFind);
 			}
 		}
+	}
 
-		{
-			for (auto& syncData : mCoreSyncData)
-			{
-				auto iterFind = syncData.entries.find(internalId);
-				if (iterFind != syncData.entries.end())
-				{
-					UINT8* data = iterFind->second.syncData.getBuffer();
-
-					if (data != nullptr && syncData.alloc != nullptr)
-						syncData.alloc->dealloc(data);
-
-					syncData.entries.erase(iterFind);
-				}
-			}
-		}
+	void CoreObjectManager::syncToCore(CoreAccessor& accessor)
+	{
+		syncDownload(gCoreThread().getFrameAlloc());
+		accessor.queueCommand(std::bind(&CoreObjectManager::syncUpload, this));
 	}
 
-	void CoreObjectManager::syncDownload(CoreObjectSync type, FrameAlloc* allocator)
+	void CoreObjectManager::syncDownload(FrameAlloc* allocator)
 	{
 		BS_LOCK_MUTEX(mObjectsMutex);
 
-		if (type == CoreObjectSync::Sim)
-		{
-			mCoreSyncData.push_back(CoreStoredSyncData());
-			CoreStoredSyncData& syncData = mCoreSyncData.back();
+		mCoreSyncData.push_back(CoreStoredSyncData());
+		CoreStoredSyncData& syncData = mCoreSyncData.back();
 
-			syncData.alloc = allocator;
-			for (auto& objectData : mObjects)
-			{
-				CoreObject* object = objectData.second;
-				SPtr<CoreObjectCore> objectCore = object->getCore();
-				if (objectCore != nullptr && object->isCoreDirty())
-				{
-					CoreSyncData objSyncData = object->syncToCore(allocator);
-					object->markCoreClean();
-
-					syncData.entries[object->getInternalID()] = CoreStoredSyncObjData(objectCore.get(), objSyncData);
-				}
-			}
-		}
-		else
+		syncData.alloc = allocator;
+		for (auto& objectData : mObjects)
 		{
-			mSimSyncData.push_back(SimStoredSyncData());
-			SimStoredSyncData& syncData = mSimSyncData.back();
-
-			syncData.alloc = allocator;
-			for (auto& objectData : mObjects)
+			CoreObject* object = objectData.second;
+			SPtr<CoreObjectCore> objectCore = object->getCore();
+			if (objectCore != nullptr && object->isCoreDirty())
 			{
-				CoreObject* object = objectData.second;
-				SPtr<CoreObjectCore> objectCore = object->getCore();
-				if (objectCore != nullptr && objectCore->isCoreDirty())
-				{
-					CoreSyncData objSyncData = objectCore->syncFromCore(allocator);
-					objectCore->markCoreClean();
-
-					syncData.entries[object->getInternalID()] = SimStoredSyncObjData(object, objSyncData);
-				}
+				CoreSyncData objSyncData = object->syncToCore(allocator);
+				object->markCoreClean();
+
+				syncData.entries[object->getInternalID()] = CoreStoredSyncObjData(objectCore.get(), objSyncData);
 			}
 		}
 	}
 
-	void CoreObjectManager::syncUpload(CoreObjectSync type)
+	void CoreObjectManager::syncUpload()
 	{
 		BS_LOCK_MUTEX(mObjectsMutex);
 
-		if (type == CoreObjectSync::Sim)
-		{
-			if (mCoreSyncData.size() == 0)
-				return;
-
-			CoreStoredSyncData& syncData = mCoreSyncData.front();
-
-			for (auto& objectData : syncData.entries)
-			{
-				const CoreStoredSyncObjData& objSyncData = objectData.second;
-				objSyncData.destinationObj->syncToCore(objSyncData.syncData);
+		if (mCoreSyncData.size() == 0)
+			return;
 
-				UINT8* data = objSyncData.syncData.getBuffer();
+		CoreStoredSyncData& syncData = mCoreSyncData.front();
 
-				if (data != nullptr)
-					syncData.alloc->dealloc(data);
-			}
-
-			syncData.entries.clear();
-			mCoreSyncData.pop_front();
-		}
-		else
+		for (auto& objectData : syncData.entries)
 		{
-			if (mSimSyncData.size() == 0)
-				return;
+			const CoreStoredSyncObjData& objSyncData = objectData.second;
+			objSyncData.destinationObj->syncToCore(objSyncData.syncData);
 
-			SimStoredSyncData& syncData = mSimSyncData.front();
+			UINT8* data = objSyncData.syncData.getBuffer();
 
-			for (auto& objectData : syncData.entries)
-			{
-				const SimStoredSyncObjData& objSyncData = objectData.second;
-				objSyncData.destinationObj->syncFromCore(objSyncData.syncData);
-
-				UINT8* data = objSyncData.syncData.getBuffer();
-
-				if (data != nullptr)
-					syncData.alloc->dealloc(data);
-			}
-
-			syncData.entries.clear();
-			mSimSyncData.pop_front();
+			if (data != nullptr)
+				syncData.alloc->dealloc(data);
 		}
+
+		syncData.entries.clear();
+		mCoreSyncData.pop_front();
 	}
 }

+ 14 - 0
BansheeCore/Source/BsFont.cpp

@@ -83,6 +83,20 @@ namespace BansheeEngine
 		return bestSize;
 	}
 
+	bool Font::areDependenciesLoaded() const
+	{
+		for (auto& fontDataEntry : mFontDataPerSize)
+		{
+			for (auto& texture : fontDataEntry.second.texturePages)
+			{
+				if (!texture.isLoaded())
+					return false;
+			}
+		}
+
+		return true;
+	}
+
 	void Font::getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies)
 	{
 		for (auto& fontDataEntry : mFontDataPerSize)

+ 3 - 52
BansheeCore/Source/BsMaterial.cpp

@@ -1069,66 +1069,17 @@ namespace BansheeEngine
 		}
 	}
 
-	bool Material::checkIfDependenciesLoaded() const
+	bool Material::areDependenciesLoaded() const
 	{
 		if (mShader == nullptr) // No shader, so everything is technically loaded
 			return true;
 
-		if (!mShader.isLoaded())
-			return false;
-
-		TechniquePtr bestTechnique = mShader->getBestTechnique();
-		if (bestTechnique == nullptr) // No valid technique, so everything is technically loaded
-			return true;
-
-		UINT32 numPasses = bestTechnique->getNumPasses();
-		for (UINT32 i = 0; i < numPasses; i++)
-		{
-			PassPtr pass = bestTechnique->getPass(i);
-
-			HGpuProgram vertProg = pass->getVertexProgram();
-			if (vertProg != nullptr && !vertProg.isLoaded())
-				return false;
-
-			HGpuProgram fragProg = pass->getFragmentProgram();
-			if (fragProg != nullptr && !fragProg.isLoaded())
-				return false;
-
-			HGpuProgram geomProg = pass->getGeometryProgram();
-			if (geomProg != nullptr && !geomProg.isLoaded())
-				return false;
-
-			HGpuProgram domProg = pass->getDomainProgram();
-			if (domProg != nullptr && !domProg.isLoaded())
-				return false;
-
-			HGpuProgram hullProg = pass->getHullProgram();
-			if (hullProg != nullptr && !hullProg.isLoaded())
-				return false;
-
-			HGpuProgram computeProg = pass->getComputeProgram();
-			if (computeProg != nullptr && !computeProg.isLoaded())
-				return false;
-
-			HBlendState blendState = pass->getBlendState();
-			if (blendState != nullptr && !blendState.isLoaded())
-				return false;
-
-			HRasterizerState rasterizerState = pass->getRasterizerState();
-			if (rasterizerState != nullptr && !rasterizerState.isLoaded())
-				return false;
-
-			HDepthStencilState depthStencilState = pass->getDepthStencilState();
-			if (depthStencilState != nullptr && !depthStencilState.isLoaded())
-				return false;
-		}
-
-		return true;
+		return mShader.isLoaded();
 	}
 
 	void Material::initializeIfLoaded()
 	{
-		if (checkIfDependenciesLoaded())
+		if (areDependenciesLoaded())
 		{
 			if (mLoadFlags != Load_All)
 			{

+ 2 - 1
BansheeCore/Source/BsMesh.cpp

@@ -266,7 +266,8 @@ namespace BansheeEngine
 	void MeshCore::updateBounds(const MeshData& meshData)
 	{
 		mProperties.mBounds = meshData.calculateBounds();
-		markCoreDirty();
+		
+		// TODO - Sync this to sim-thread possibly?
 	}
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 

+ 0 - 14
BansheeCore/Source/BsMeshBase.cpp

@@ -44,15 +44,6 @@ namespace BansheeEngine
 		:mProperties(numVertices, numIndices, subMeshes)
 	{ }
 
-	CoreSyncData MeshCoreBase::syncFromCore(FrameAlloc* allocator)
-	{
-		UINT32 size = sizeof(Bounds);
-		UINT8* buffer = allocator->alloc(size);
-
-		memcpy(buffer, &mProperties.mBounds, size);
-		return CoreSyncData(buffer, size);
-	}
-
 	void MeshCoreBase::syncToCore(const CoreSyncData& data)
 	{
 		mProperties.mBounds = data.getData<Bounds>();
@@ -78,11 +69,6 @@ namespace BansheeEngine
 		return CoreSyncData(buffer, size);
 	}
 
-	void MeshBase::syncFromCore(const CoreSyncData& data)
-	{
-		mProperties.mBounds = data.getData<Bounds>();
-	}
-
 	SPtr<MeshCoreBase> MeshBase::getCore() const
 	{
 		return std::static_pointer_cast<MeshCoreBase>(mCoreSpecific);

+ 0 - 17
BansheeCore/Source/BsMultiRenderTexture.cpp

@@ -114,17 +114,6 @@ namespace BansheeEngine
 		throwIfBuffersDontMatch();
 	}
 
-	CoreSyncData MultiRenderTextureCore::syncFromCore(FrameAlloc* allocator)
-	{
-		UINT32 size = sizeof(MultiRenderTextureProperties);
-		UINT8* buffer = allocator->alloc(size);
-
-		MultiRenderTextureProperties& props = const_cast<MultiRenderTextureProperties&>(getProperties());
-
-		memcpy(buffer, &props, size);
-		return CoreSyncData(buffer, size);
-	}
-
 	void MultiRenderTextureCore::syncToCore(const CoreSyncData& data)
 	{
 		MultiRenderTextureProperties& props = const_cast<MultiRenderTextureProperties&>(getProperties());
@@ -265,12 +254,6 @@ namespace BansheeEngine
 		return CoreSyncData(buffer, size);
 	}
 
-	void MultiRenderTexture::syncFromCore(const CoreSyncData& data)
-	{
-		MultiRenderTextureProperties& props = const_cast<MultiRenderTextureProperties&>(getProperties());
-		props = data.getData<MultiRenderTextureProperties>();
-	}
-
 	const MultiRenderTextureProperties& MultiRenderTexture::getProperties() const
 	{
 		return static_cast<const MultiRenderTextureProperties&>(getPropertiesInternal());

+ 1 - 0
BansheeCore/Source/BsRenderAPI.cpp

@@ -122,6 +122,7 @@ namespace BansheeEngine
 
 	void RenderAPI::bindGpuProgram(CoreAccessor& accessor, const GpuProgramPtr& prg)
 	{
+		prg->syncToCore(accessor);
 		accessor.queueCommand(std::bind(&RenderAPICore::bindGpuProgram, RenderAPICore::instancePtr(), prg->getCore()));
 	}
 

+ 0 - 9
BansheeCore/Source/BsRenderTarget.cpp

@@ -12,20 +12,11 @@ namespace BansheeEngine
 
 	}
 
-	void RenderTargetCore::setActive(bool state)
-	{ 
-		RenderTargetProperties& props = const_cast<RenderTargetProperties&>(getProperties());
-
-		props.mActive = state;
-		markCoreDirty();
-	}
-
 	void RenderTargetCore::setPriority(INT32 priority) 
 	{ 
 		RenderTargetProperties& props = const_cast<RenderTargetProperties&>(getProperties());
 
 		props.mPriority = priority;
-		markCoreDirty();
 	}
 
 	const RenderTargetProperties& RenderTargetCore::getProperties() const

+ 0 - 17
BansheeCore/Source/BsRenderTexture.cpp

@@ -114,17 +114,6 @@ namespace BansheeEngine
 		}
 	}
 
-	CoreSyncData RenderTextureCore::syncFromCore(FrameAlloc* allocator)
-	{
-		UINT32 size = sizeof(RenderTextureProperties);
-		UINT8* buffer = allocator->alloc(size);
-
-		RenderTextureProperties& props = const_cast<RenderTextureProperties&>(getProperties());
-
-		memcpy(buffer, &props, size);
-		return CoreSyncData(buffer, size);
-	}
-
 	void RenderTextureCore::syncToCore(const CoreSyncData& data)
 	{
 		RenderTextureProperties& props = const_cast<RenderTextureProperties&>(getProperties());
@@ -214,12 +203,6 @@ namespace BansheeEngine
 		return CoreSyncData(buffer, size);
 	}
 
-	void RenderTexture::syncFromCore(const CoreSyncData& data)
-	{
-		RenderTextureProperties& props = const_cast<RenderTextureProperties&>(getProperties());
-		props = data.getData<RenderTextureProperties>();
-	}
-
 	const RenderTextureProperties& RenderTexture::getProperties() const
 	{
 		return static_cast<const RenderTextureProperties&>(getPropertiesInternal());

+ 9 - 22
BansheeCore/Source/BsRenderWindow.cpp

@@ -42,15 +42,14 @@ namespace BansheeEngine
 		THROW_IF_NOT_CORE_THREAD;
 	}
 
-	CoreSyncData RenderWindowCore::syncFromCore(FrameAlloc* allocator)
+	void RenderWindowCore::setActive(bool state)
 	{
-		UINT32 size = sizeof(RenderWindowProperties);
-		UINT8* buffer = allocator->alloc(size);
+		THROW_IF_NOT_CORE_THREAD;
 
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 
-		memcpy(buffer, &props, size);
-		return CoreSyncData(buffer, size);
+		props.mActive = state;
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
 	void RenderWindowCore::syncToCore(const CoreSyncData& data)
@@ -62,6 +61,8 @@ namespace BansheeEngine
 	void RenderWindowCore::_windowMovedOrResized()
 	{
 		THROW_IF_NOT_CORE_THREAD;
+
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void RenderWindowCore::_windowFocusReceived()
@@ -71,7 +72,7 @@ namespace BansheeEngine
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		properties.mHasFocus = true;
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyFocusReceived(this);
 	}
 
 	void RenderWindowCore::_windowFocusLost()
@@ -81,7 +82,7 @@ namespace BansheeEngine
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		properties.mHasFocus = false;
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyFocusLost(this);
 	}
 
 	const RenderWindowProperties& RenderWindowCore::getProperties() const
@@ -91,7 +92,7 @@ namespace BansheeEngine
 
 	void RenderWindow::destroy()
 	{
-		RenderWindowManager::instance().windowDestroyed(this);
+		RenderWindowManager::instance().notifyWindowDestroyed(this);
 
 		RenderTarget::destroy();
 	}
@@ -207,20 +208,6 @@ namespace BansheeEngine
 		return CoreSyncData(buffer, size);
 	}
 
-	void RenderWindow::syncFromCore(const CoreSyncData& data)
-	{
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-
-		const RenderWindowProperties& newProps = data.getData<RenderWindowProperties>();
-
-		bool movedOrResized = props.getHeight() != newProps.getHeight() || props.getWidth() != newProps.getWidth() || props.getLeft() != newProps.getLeft()
-			|| props.getTop() != newProps.getTop() || props.isFullScreen() != newProps.isFullScreen();
-
-		props = newProps;
-		if (movedOrResized)
-			RenderWindowManager::instance().windowMovedOrResized(this);
-	}
-
 	const RenderWindowProperties& RenderWindow::getProperties() const
 	{
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());

+ 76 - 9
BansheeCore/Source/BsRenderWindowManager.cpp

@@ -8,11 +8,22 @@ namespace BansheeEngine
 	RenderWindowManager::RenderWindowManager()
 		:mWindowInFocus(nullptr), mNewWindowInFocus(nullptr)
 	{
-		Platform::onWindowFocusReceived.connect(std::bind(&RenderWindowManager::windowFocusReceived, this, _1));
-		Platform::onWindowFocusLost.connect(std::bind(&RenderWindowManager::windowFocusLost, this, _1));
 		Platform::onMouseLeftWindow.connect(std::bind(&RenderWindowManager::windowMouseLeft, this, _1));
 	}
 
+	RenderWindowManager::~RenderWindowManager()
+	{
+		for (auto& dirtyPropertyEntry : mDirtyProperties)
+		{
+			DirtyPropertyData& dirtyPropertyData = dirtyPropertyEntry.second;
+
+			if (dirtyPropertyEntry.second.data != nullptr)
+				bs_delete(dirtyPropertyEntry.second.data);
+		}
+
+		mDirtyProperties.clear();
+	}
+
 	RenderWindowPtr RenderWindowManager::create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
 	{
 		RenderWindowPtr renderWindow = createImpl(desc, parentWindow);
@@ -29,7 +40,7 @@ namespace BansheeEngine
 		return renderWindow;
 	}
 
-	void RenderWindowManager::windowDestroyed(RenderWindow* window)
+	void RenderWindowManager::notifyWindowDestroyed(RenderWindow* window)
 	{
 		{
 			BS_LOCK_MUTEX(mWindowMutex);
@@ -46,29 +57,43 @@ namespace BansheeEngine
 			if(iterFind2 != mMovedOrResizedWindows.end())
 				mMovedOrResizedWindows.erase(iterFind2);
 
+			auto iterFind3 = mDirtyProperties.find(window);
+			if (iterFind3 != mDirtyProperties.end())
+			{
+				if (iterFind3->second.data != nullptr)
+					bs_delete(iterFind3->second.data);
+
+				mDirtyProperties.erase(iterFind3);
+			}
+
 			mCoreToNonCoreMap.erase(window->getCore().get());
 		}
 	}
 
-	void RenderWindowManager::windowFocusReceived(RenderWindowCore* coreWindow)
+	void RenderWindowManager::notifyFocusReceived(RenderWindowCore* coreWindow)
 	{
-		coreWindow->_windowFocusReceived();
 		RenderWindow* window = getNonCore(coreWindow);
 
 		BS_LOCK_MUTEX(mWindowMutex);
 		mNewWindowInFocus = window;
+
+		setDirtyProperties(coreWindow);
 	}
 
-	void RenderWindowManager::windowFocusLost(RenderWindowCore* window)
+	void RenderWindowManager::notifyFocusLost(RenderWindowCore* coreWindow)
 	{
-		window->_windowFocusLost();
+		RenderWindow* window = getNonCore(coreWindow);
 
 		BS_LOCK_MUTEX(mWindowMutex);
 		mNewWindowInFocus = nullptr;
+
+		setDirtyProperties(coreWindow);
 	}
 
-	void RenderWindowManager::windowMovedOrResized(RenderWindow* window)
+	void RenderWindowManager::notifyMovedOrResized(RenderWindowCore* coreWindow)
 	{
+		RenderWindow* window = getNonCore(coreWindow);
+
 		bool isValidWindow = false;
 		{
 			BS_LOCK_MUTEX(mWindowMutex);
@@ -83,8 +108,37 @@ namespace BansheeEngine
 
 		auto iterFind = std::find(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), window);
 
-		if(iterFind == end(mMovedOrResizedWindows))
+		if (iterFind == end(mMovedOrResizedWindows))
 			mMovedOrResizedWindows.push_back(window);
+
+		setDirtyProperties(coreWindow);
+	}
+
+	void RenderWindowManager::notifyPropertiesDirty(RenderWindowCore* coreWindow)
+	{
+		RenderWindow* window = getNonCore(coreWindow);
+
+		BS_LOCK_MUTEX(mWindowMutex);
+		setDirtyProperties(coreWindow);
+	}
+
+	void RenderWindowManager::setDirtyProperties(RenderWindowCore* coreWindow)
+	{
+		RenderWindow* window = getNonCore(coreWindow);
+
+		auto iterFind = mDirtyProperties.find(window);
+		if (iterFind != mDirtyProperties.end())
+		{
+			if (iterFind->second.data != nullptr)
+				bs_delete(iterFind->second.data);
+		}
+
+		mDirtyProperties[window] = DirtyPropertyData();
+		DirtyPropertyData& dirtyPropertyData = mDirtyProperties[window];
+		dirtyPropertyData.size = coreWindow->getSyncData(nullptr);
+		dirtyPropertyData.data = (UINT8*)bs_alloc(dirtyPropertyData.size);
+
+		coreWindow->getSyncData(dirtyPropertyData.data);
 	}
 
 	void RenderWindowManager::windowMouseLeft(RenderWindowCore* coreWindow)
@@ -113,6 +167,19 @@ namespace BansheeEngine
 
 			mouseLeftWindows = mMouseLeftWindows;
 			mMouseLeftWindows.clear();
+
+			for (auto& dirtyPropertyEntry : mDirtyProperties)
+			{
+				RenderWindow* window = dirtyPropertyEntry.first;
+				DirtyPropertyData& dirtyPropertyData = dirtyPropertyEntry.second;
+
+				window->setSyncData(dirtyPropertyData.data, dirtyPropertyData.size);
+
+				if (dirtyPropertyEntry.second.data != nullptr)
+					bs_delete(dirtyPropertyEntry.second.data);
+			}
+
+			mDirtyProperties.clear();
 		}
 
 		if(mWindowInFocus != newWinInFocus)

+ 7 - 2
BansheeCore/Source/BsResourceHandle.cpp

@@ -20,9 +20,14 @@ namespace BansheeEngine
 
 	}
 
-	bool ResourceHandleBase::isLoaded() const 
+	bool ResourceHandleBase::isLoaded(bool checkDependencies) const 
 	{ 
-		return (mData != nullptr && mData->mIsCreated && mData->mPtr != nullptr); 
+		bool isLoaded = (mData != nullptr && mData->mIsCreated && mData->mPtr != nullptr);
+
+		if (checkDependencies && isLoaded)
+			isLoaded = mData->mPtr->areDependenciesLoaded();
+
+		return isLoaded;
 	}
 
 	void ResourceHandleBase::blockUntilLoaded() const

+ 52 - 0
BansheeCore/Source/BsShader.cpp

@@ -5,6 +5,7 @@
 #include "BsShaderRTTI.h"
 #include "BsResources.h"
 #include "BsFrameAlloc.h"
+#include "BsPass.h"
 
 namespace BansheeEngine
 {
@@ -198,6 +199,57 @@ namespace BansheeEngine
 		return shaderCorePtr;
 	}
 
+	bool Shader::areDependenciesLoaded() const
+	{
+		TechniquePtr bestTechnique = getBestTechnique();
+		if (bestTechnique == nullptr) // No valid technique, so everything is technically loaded
+			return true;
+
+		UINT32 numPasses = bestTechnique->getNumPasses();
+		for (UINT32 i = 0; i < numPasses; i++)
+		{
+			PassPtr pass = bestTechnique->getPass(i);
+
+			HGpuProgram vertProg = pass->getVertexProgram();
+			if (vertProg != nullptr && !vertProg.isLoaded())
+				return false;
+
+			HGpuProgram fragProg = pass->getFragmentProgram();
+			if (fragProg != nullptr && !fragProg.isLoaded())
+				return false;
+
+			HGpuProgram geomProg = pass->getGeometryProgram();
+			if (geomProg != nullptr && !geomProg.isLoaded())
+				return false;
+
+			HGpuProgram domProg = pass->getDomainProgram();
+			if (domProg != nullptr && !domProg.isLoaded())
+				return false;
+
+			HGpuProgram hullProg = pass->getHullProgram();
+			if (hullProg != nullptr && !hullProg.isLoaded())
+				return false;
+
+			HGpuProgram computeProg = pass->getComputeProgram();
+			if (computeProg != nullptr && !computeProg.isLoaded())
+				return false;
+
+			HBlendState blendState = pass->getBlendState();
+			if (blendState != nullptr && !blendState.isLoaded())
+				return false;
+
+			HRasterizerState rasterizerState = pass->getRasterizerState();
+			if (rasterizerState != nullptr && !rasterizerState.isLoaded())
+				return false;
+
+			HDepthStencilState depthStencilState = pass->getDepthStencilState();
+			if (depthStencilState != nullptr && !depthStencilState.isLoaded())
+				return false;
+		}
+
+		return true;
+	}
+
 	void Shader::getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies)
 	{
 		for (auto& technique : mTechniques)

+ 0 - 21
BansheeCore/Source/Win32/BsPlatformImpl.cpp

@@ -17,9 +17,6 @@ namespace BansheeEngine
 	Event<void(float)> Platform::onMouseWheelScrolled;
 	Event<void(UINT32)> Platform::onCharInput;
 
-	Event<void(RenderWindowCore*)> Platform::onWindowFocusReceived;
-	Event<void(RenderWindowCore*)> Platform::onWindowFocusLost;
-	Event<void(RenderWindowCore*)> Platform::onWindowMovedOrResized;
 	Event<void(RenderWindowCore*)> Platform::onMouseLeftWindow;
 	Event<void()> Platform::onMouseCaptureChanged;
 
@@ -509,24 +506,6 @@ namespace BansheeEngine
 		mRequiresShutDown = true;
 	}
 
-	void Platform::windowFocusReceived(RenderWindowCore* window)
-	{
-		if(!onWindowFocusReceived.empty())
-			onWindowFocusReceived(window);
-	}
-
-	void Platform::windowFocusLost(RenderWindowCore* window)
-	{
-		if(!onWindowFocusLost.empty())
-			onWindowFocusLost(window);
-	}
-	
-	void Platform::windowMovedOrResized(RenderWindowCore* window)
-	{
-		if(!onWindowMovedOrResized.empty())
-			onWindowMovedOrResized(window);
-	}
-
 	void Platform::win32ShowCursor()
 	{
 		SetCursor(mCursor.data->cursor);

+ 2 - 5
BansheeCore/Source/Win32/BsPlatformWndProc.cpp

@@ -118,14 +118,14 @@ namespace BansheeEngine
 		case WM_SETFOCUS:
 			{
 				if (!win->getProperties().hasFocus())
-					windowFocusReceived(win);
+					win->_windowFocusReceived();
 
 				break;
 			}
 		case WM_KILLFOCUS:
 			{
 				if (win->getProperties().hasFocus())
-					windowFocusLost(win);
+					win->_windowFocusLost();
 
 				break;
 			}
@@ -136,15 +136,12 @@ namespace BansheeEngine
 			break;
 		case WM_MOVE:
 			win->_windowMovedOrResized();
-			windowMovedOrResized(win);
 			break;
 		case WM_DISPLAYCHANGE:
 			win->_windowMovedOrResized();
-			windowMovedOrResized(win);
 			break;
 		case WM_SIZE:
 			win->_windowMovedOrResized();
-			windowMovedOrResized(win);
 			break;
 		case WM_SETCURSOR:
 			if(isCursorHidden())

+ 10 - 0
BansheeD3D11RenderSystem/Include/BsD3D11RenderWindow.h

@@ -140,6 +140,11 @@ namespace BansheeEngine
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
+		/**
+		 * @copydoc	RenderWindowCore::getSyncData
+		 */
+		UINT32 getSyncData(UINT8* buffer);
+
 	protected:
 		D3D11Device& mDevice;
 		IDXGIFactory* mDXGIFactory;
@@ -204,6 +209,11 @@ namespace BansheeEngine
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
+		/**
+		 * @copydoc	RenderWindow::setSyncData
+		 */
+		void setSyncData(UINT8* buffer, UINT32 size);
+
 		/**
 		 * @brief	Retrieves internal window handle.
 		 */

+ 22 - 7
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -12,6 +12,7 @@
 #include "BsRenderStats.h"
 #include "BsInput.h"
 #include "BsException.h"
+#include "BsRenderWindowManager.h"
 
 namespace BansheeEngine
 {
@@ -30,7 +31,6 @@ namespace BansheeEngine
 		D3D11RenderWindowProperties& props = mProperties;
 
 		props.mActive = false;
-		markCoreDirty();
 
 		SAFE_RELEASE(mSwapChain);
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_SwapChain);
@@ -356,7 +356,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
 	void D3D11RenderWindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
@@ -397,7 +397,7 @@ namespace BansheeEngine
 		mSwapChain->ResizeTarget(&nearestMode);
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput()); 
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void D3D11RenderWindowCore::setFullscreen(const VideoMode& mode)
@@ -430,7 +430,7 @@ namespace BansheeEngine
 		mSwapChain->ResizeTarget(&videoMode.getDXGIModeDesc());
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput());
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void D3D11RenderWindowCore::setWindowed(UINT32 width, UINT32 height)
@@ -459,7 +459,7 @@ namespace BansheeEngine
 		mSwapChain->SetFullscreenState(false, nullptr);
 		mSwapChain->ResizeTarget(&modeDesc);
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	HWND D3D11RenderWindowCore::_getWindowHandle() const
@@ -575,7 +575,6 @@ namespace BansheeEngine
 
 		mProperties.mTop = rc.top;
 		mProperties.mLeft = rc.left;
-		markCoreDirty();
 
 		GetClientRect(mHWnd, &rc);
 		unsigned int width = rc.right - rc.left;
@@ -714,13 +713,22 @@ namespace BansheeEngine
 		mProperties.mWidth = mSwapChainDesc.BufferDesc.Width;
 		mProperties.mHeight = mSwapChainDesc.BufferDesc.Height;
 		mProperties.mIsFullScreen = (0 == mSwapChainDesc.Windowed); // Alt-Enter together with SetWindowAssociation() can change this state
-		markCoreDirty();
 
 		createSizeDependedD3DResources();
 
 		mDevice.getImmediateContext()->OMSetRenderTargets(0, 0, 0);
 	}
 
+	UINT32 D3D11RenderWindowCore::getSyncData(UINT8* buffer)
+	{
+		UINT32 size = sizeof(mProperties);
+
+		if (buffer != nullptr)
+			memcpy(buffer, &mProperties, size);
+
+		return size;
+	}
+
 	IDXGIDevice* D3D11RenderWindowCore::queryDxgiDevice()
 	{
 		if (mDevice.getD3D11Device() == nullptr)
@@ -773,6 +781,13 @@ namespace BansheeEngine
 		return Vector2I(pos.x, pos.y);
 	}
 
+	void D3D11RenderWindow::setSyncData(UINT8* buffer, UINT32 size)
+	{
+		assert(size == sizeof(mProperties));
+
+		memcpy(&mProperties, buffer, size);
+	}
+
 	SPtr<D3D11RenderWindowCore> D3D11RenderWindow::getCore() const
 	{
 		return std::static_pointer_cast<D3D11RenderWindowCore>(mCoreSpecific);

+ 10 - 0
BansheeD3D9RenderSystem/Include/BsD3D9RenderWindow.h

@@ -147,6 +147,11 @@ namespace BansheeEngine
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
+		/**
+		 * @copydoc	RenderWindowCore::getSyncData
+		 */
+		UINT32 getSyncData(UINT8* buffer);
+
 	protected:
 		HINSTANCE mInstance;
 		D3D9Device* mDevice;
@@ -207,6 +212,11 @@ namespace BansheeEngine
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
+		/**
+		 * @copydoc	RenderWindow::setSyncData
+		 */
+		void setSyncData(UINT8* buffer, UINT32 size);
+
 		/**
 		 * @brief	Retrieves internal window handle.
 		 */

+ 20 - 8
BansheeD3D9RenderSystem/Source/BsD3D9RenderWindow.cpp

@@ -9,6 +9,7 @@
 #include "Win32/BsPlatformWndProc.h"
 #include "BsD3D9VideoModeInfo.h"
 #include "BsD3D9DeviceManager.h"
+#include "BsRenderWindowManager.h"
 
 namespace BansheeEngine
 {
@@ -38,8 +39,6 @@ namespace BansheeEngine
 
 		mHWnd = 0;
 		mProperties.mActive = false;
-
-		markCoreDirty();
 	}
 
 	void D3D9RenderWindowCore::initialize()
@@ -278,7 +277,7 @@ namespace BansheeEngine
 		mDevice->invalidate(this);
 		mDevice->acquire();
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void D3D9RenderWindowCore::setFullscreen(const VideoMode& mode)
@@ -326,7 +325,7 @@ namespace BansheeEngine
 		mDevice->invalidate(this);
 		mDevice->acquire();
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void D3D9RenderWindowCore::setHidden(bool hidden)
@@ -344,7 +343,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
 	void D3D9RenderWindowCore::move(INT32 top, INT32 left)
@@ -640,7 +639,6 @@ namespace BansheeEngine
 			props.mWidth = 0;
 			props.mHeight = 0;
 
-			markCoreDirty();
 			return;
 		}
 		
@@ -656,14 +654,21 @@ namespace BansheeEngine
 			props.mWidth = 0;
 			props.mHeight = 0;
 
-			markCoreDirty();
 			return;
 		}
 
 		props.mWidth = rc.right - rc.left;
 		props.mHeight = rc.bottom - rc.top;
+	}
+
+	UINT32 D3D9RenderWindowCore::getSyncData(UINT8* buffer)
+	{
+		UINT32 size = sizeof(mProperties);
+
+		if (buffer != nullptr)
+			memcpy(buffer, &mProperties, size);
 
-		markCoreDirty();
+		return size;
 	}
 
 	bool D3D9RenderWindowCore::_validateDevice()
@@ -708,6 +713,13 @@ namespace BansheeEngine
 		return Vector2I(pos.x, pos.y);
 	}
 
+	void D3D9RenderWindow::setSyncData(UINT8* buffer, UINT32 size)
+	{
+		assert(size == sizeof(mProperties));
+
+		memcpy(&mProperties, buffer, size);
+	}
+
 	HWND D3D9RenderWindow::getHWnd() const
 	{
 		// HACK: I'm accessing core method from sim thread, which means an invalid handle

+ 5 - 0
BansheeEngine/Include/BsSpriteTexture.h

@@ -64,6 +64,11 @@ namespace BansheeEngine
 		 */
 		SpriteTexture(const Vector2& uvOffset, const Vector2& uvScale, const HTexture& texture);
 
+		/**
+		 * @copydoc	Resource::areDependenciesLoaded
+		 */
+		bool areDependenciesLoaded() const;
+
 		/**
 		 * @copydoc	CoreObject::getCoreDependencies
 		 */

+ 5 - 0
BansheeEngine/Source/BsSpriteTexture.cpp

@@ -43,6 +43,11 @@ namespace BansheeEngine
 		return Math::roundToInt(mAtlasTexture->getProperties().getHeight() * mUVScale.y);
 	}
 
+	bool SpriteTexture::areDependenciesLoaded() const
+	{
+		return mAtlasTexture.isLoaded();
+	}
+
 	void SpriteTexture::getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies)
 	{
 		if (mAtlasTexture.isLoaded())

+ 11 - 1
BansheeGLRenderSystem/Include/BsWin32Window.h

@@ -105,6 +105,11 @@ namespace BansheeEngine
 		 */
 		virtual void initialize();
 
+		/**
+		 * @copydoc	RenderWindowCore::getSyncData
+		 */
+		UINT32 getSyncData(UINT8* buffer);
+		
 		/**
 		 * @brief	Calculates window size based on provided client area size and currently set window style. 
 		 */
@@ -168,10 +173,15 @@ namespace BansheeEngine
 		Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport& glsupport);
 
 		/**
-		 * @copydoc	RenderWindowCore::getProperties
+		 * @copydoc	RenderWindow::getProperties
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
+		/**
+		 * @copydoc	RenderWindow::setSyncData
+		 */
+		void setSyncData(UINT8* buffer, UINT32 size);
+
 		/**
 		 * @brief	Retrieves internal window handle.
 		 */

+ 21 - 9
BansheeGLRenderSystem/Source/BsWin32Window.cpp

@@ -12,6 +12,7 @@
 #include "Win32/BsPlatformWndProc.h"
 #include "BsWin32VideoModeInfo.h"
 #include "BsGLPixelFormat.h"
+#include "BsRenderWindowManager.h"
 
 GLenum GLEWAPIENTRY wglewContextInit(BansheeEngine::GLSupport *glSupport);
 
@@ -56,8 +57,6 @@ namespace BansheeEngine
 			bs_free<ScratchAlloc>(mDeviceName);
 			mDeviceName = NULL;
 		}
-
-		markCoreDirty();
 	}
 
 	void Win32WindowCore::initialize()
@@ -402,7 +401,7 @@ namespace BansheeEngine
 
 		SetWindowPos(mHWnd, HWND_TOP, props.mLeft, props.mTop, width, height, SWP_NOACTIVATE);
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 
 	void Win32WindowCore::setFullscreen(const VideoMode& mode)
@@ -451,8 +450,6 @@ namespace BansheeEngine
 			SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
 
 		_windowMovedOrResized();
-
-		markCoreDirty();
 	}
 
 	void Win32WindowCore::move(INT32 left, INT32 top)
@@ -618,7 +615,7 @@ namespace BansheeEngine
 			}
 		}
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
 	void Win32WindowCore::setHidden(bool hidden)
@@ -635,7 +632,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 
-		markCoreDirty();
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
 	void Win32WindowCore::_windowMovedOrResized()
@@ -654,8 +651,6 @@ namespace BansheeEngine
 		props.mWidth = rc.right - rc.left;
 		props.mHeight = rc.bottom - rc.top;
 
-		markCoreDirty();
-
 		RenderWindowCore::_windowMovedOrResized();
 	}
 
@@ -689,6 +684,16 @@ namespace BansheeEngine
 			*winHeight = maxH;
 	}
 
+	UINT32 Win32WindowCore::getSyncData(UINT8* buffer)
+	{
+		UINT32 size = sizeof(mProperties);
+
+		if (buffer != nullptr)
+			memcpy(buffer, &mProperties, size);
+
+		return size;
+	}
+
 	Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport)
 		:RenderWindow(desc), mGLSupport(glsupport), mProperties(desc)
 	{
@@ -730,6 +735,13 @@ namespace BansheeEngine
 		return std::static_pointer_cast<Win32WindowCore>(mCoreSpecific);
 	}
 
+	void Win32Window::setSyncData(UINT8* buffer, UINT32 size)
+	{
+		assert(size == sizeof(mProperties));
+		
+		memcpy(&mProperties, buffer, size);
+	}
+
 	HWND Win32Window::getHWnd() const
 	{
 		// HACK: I'm accessing core method from sim thread, which means an invalid handle

+ 13 - 12
TODO.txt

@@ -7,18 +7,18 @@ ManagedSerializeArray::deserializeManagedInstance were reported as ManagedSerial
 It's inconsistent to reproduce but started happening after I have modified managed object serialization to be on-demand. It's possibly
 related to lambdas not capturing types as I expect them to. It always happens in the same place.
 
-Keep the sync internal to CoreObjectManager
-Add a new public syncToCore method that accepts a core accessor (possibly make it part of CoreObjectManager, to keep things consistent with method described below)
- - It only syncs that specific object and all the children
- - getCoreDependencies to get children
-Rename syncUpload, syncDownload to syncToCore
- - It will sync all objects as it does now, no change
-Add syncToCore for GpuParams when binding them from sim thread
-Possibly remove syncFromCore and replace it with custom managers
- - Remove mesh bounds sync completely
- - Remove render target sync (priority and active state)
-   - Remove RenderTargetCore::setPriority and make active state window only
- - Move anything render target related to RenderWindowManager
+Properly implement getPropertyCopy and updateProperties that are called from RenderWindowManager.
+
+Resource refresh:
+ - Keep track of every single active ScriptObject
+   - Before refresh serialize any managed component and managed resource
+   - After refresh create new instances and restore mCachedPtr fields
+   - After refresh restore managed component and managed resource serialized data
+   - Pay special attention to C# types that store custom data which might not be serialized. I'll need to handle that manually or change where that data is stored.
+   - Pay special attention to script objects that store references to MonoObject*, or MonoClass* (and similar) types (if they're not refreshed in initRuntimeData)
+ - Check non-ScriptObject classes to ensure they properly refresh any references to: MonoClass, MonoField, MonoProperty, MonoMethod, MonoAssembly, function thunk
+ - I should probably avoid calling constructor on restore since it may be doing some initialization. See how Unity does it.
+   - Unity does call the constructor
 
 I can get mono errors by checking g_print calls in goutput.c
  - Calling thunks incorrectly can cause those weird errors with no real callstack
@@ -28,6 +28,7 @@ Multi-resource saving:
  - Register it in its meta file
  - When saving such a resource with dependencies save the contained files to a sub-directory with the same name as top level resource
    - If it already exists in the manifest at a different location do it anyway, keep the other copy as-is in case user wanted it that way
+   - I'm not sure whether to do this for all Resource::save calls or only ones originating from ProjectLIbrary?
 
 Other:
 Window resize end callback