Browse Source

Added synced CommandQueue and syced deferred context (WIP)

Marko Pintera 12 years ago
parent
commit
4980cef1bc
36 changed files with 678 additions and 535 deletions
  1. 2 1
      BansheeEngine/Include/BsGUIWidget.h
  2. 2 1
      BansheeEngine/Include/BsOverlay.h
  3. 2 1
      BansheeEngine/Include/BsOverlayManager.h
  4. 2 2
      BansheeEngine/Source/BsGUIWidget.cpp
  5. 1 1
      BansheeEngine/Source/BsOverlayManager.cpp
  6. 0 3
      BansheeForwardRenderer/Include/BsForwardRenderer.h
  7. 8 9
      BansheeForwardRenderer/Source/BsForwardRenderer.cpp
  8. 1 0
      CamelotCore/CamelotCore.vcxproj
  9. 3 0
      CamelotCore/CamelotCore.vcxproj.filters
  10. 22 4
      CamelotCore/Include/CmApplication.h
  11. 170 60
      CamelotCore/Include/CmCommandQueue.h
  12. 172 38
      CamelotCore/Include/CmDeferredRenderContext.h
  13. 15 0
      CamelotCore/Include/CmDeferredRenderContextFwd.h
  14. 15 0
      CamelotCore/Include/CmGpuResource.h
  15. 2 6
      CamelotCore/Include/CmGpuResourceData.h
  16. 3 2
      CamelotCore/Include/CmPass.h
  17. 0 4
      CamelotCore/Include/CmPrerequisites.h
  18. 15 3
      CamelotCore/Include/CmRenderSystem.h
  19. 23 42
      CamelotCore/Include/CmTexture.h
  20. 16 3
      CamelotCore/Include/CmTextureRTTI.h
  21. 11 1
      CamelotCore/Source/CmApplication.cpp
  22. 52 57
      CamelotCore/Source/CmCommandQueue.cpp
  23. 0 172
      CamelotCore/Source/CmDeferredRenderContext.cpp
  24. 24 25
      CamelotCore/Source/CmPass.cpp
  25. 22 8
      CamelotCore/Source/CmRenderSystem.cpp
  26. 47 31
      CamelotCore/Source/CmTexture.cpp
  27. 6 1
      CamelotFontImporter/Source/CmFontImporter.cpp
  28. 5 1
      CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp
  29. 1 0
      CamelotUtility/CamelotUtility.vcxproj
  30. 6 0
      CamelotUtility/CamelotUtility.vcxproj.filters
  31. 5 5
      CamelotUtility/Include/CmAsyncOp.h
  32. 3 5
      CamelotUtility/Include/CmMath.h
  33. 2 0
      CamelotUtility/Include/CmThreadDefines.h
  34. 15 0
      CamelotUtility/Source/CmAsyncOp.cpp
  35. 0 5
      CamelotUtility/Source/CmMath.cpp
  36. 5 44
      TODO.txt

+ 2 - 1
BansheeEngine/Include/BsGUIWidget.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "BsOverlay.h"
 #include "BsTextSprite.h"
 #include "CmORect.h"
@@ -15,7 +16,7 @@ namespace BansheeEngine
 		void setSkin(const GUISkin* skin);
 		const GUISkin* getGUISkin() const;
 
-		virtual void render(const Camera* camera, CM::DeferredRenderContextPtr& renderContext) const;
+		virtual void render(const Camera* camera, CM::RenderContext& renderContext) const;
 	protected:
 		friend class CM::SceneObject;
 		friend class GUIElement;

+ 2 - 1
BansheeEngine/Include/BsOverlay.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmComponent.h"
 
 namespace BansheeEngine
@@ -16,7 +17,7 @@ namespace BansheeEngine
 	public:
 		virtual ~Overlay();
 
-		virtual void render(const Camera* camera, CM::DeferredRenderContextPtr& renderContext) const = 0;
+		virtual void render(const Camera* camera, CM::RenderContext& renderContext) const = 0;
 		virtual void update() {}
 
 	protected:

+ 2 - 1
BansheeEngine/Include/BsOverlayManager.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmModule.h"
 
 namespace BansheeEngine
@@ -16,7 +17,7 @@ namespace BansheeEngine
 	class BS_EXPORT OverlayManager : public CM::Module<OverlayManager>
 	{
 	public:
-		void render(const Camera* camera, CM::DeferredRenderContextPtr& renderContext) const;
+		void render(const Camera* camera, CM::RenderContext& renderContext) const;
 
 		void attachOverlay(const Camera* camera, const Overlay* overlay);
 		void detachOverlay(const Camera* camera, const Overlay* overlay);

+ 2 - 2
BansheeEngine/Source/BsGUIWidget.cpp

@@ -184,7 +184,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIWidget::render(const Camera* camera, DeferredRenderContextPtr& renderContext) const
+	void GUIWidget::render(const Camera* camera, RenderContext& renderContext) const
 	{
 		// Mesh is re-created every frame. There might be a better approach that only recreates it upon change,
 		// but for now it seems like too much hassle for something like GUI that is pretty dynamic anyway.
@@ -216,7 +216,7 @@ namespace BansheeEngine
 				PassParametersPtr paramsPtr = material->getPassParameters(i);
 				pass->bindParameters(renderContext, paramsPtr);
 
-				renderContext->render(mesh->getRenderOperation());
+				renderContext.render(mesh->getRenderOperation());
 			}
 
 			meshIdx++;

+ 1 - 1
BansheeEngine/Source/BsOverlayManager.cpp

@@ -6,7 +6,7 @@ using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	void OverlayManager::render(const Camera* camera, DeferredRenderContextPtr& renderContext) const
+	void OverlayManager::render(const Camera* camera, RenderContext& renderContext) const
 	{
 		auto overlays = mOverlaysPerCamera.find(camera);
 

+ 0 - 3
BansheeForwardRenderer/Include/BsForwardRenderer.h

@@ -15,8 +15,5 @@ namespace BansheeEngine
 
 		virtual void renderAll();
 		virtual void render(const HCamera& camera);
-
-	protected:
-		CM::RenderCommandBuffer* mCommandBuffer;
 	};
 }

+ 8 - 9
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -1,7 +1,6 @@
 #include "BsForwardRenderer.h"
 #include "BsCamera.h"
 #include "BsSceneManager.h"
-#include "CmDeferredRenderContext.h"
 #include "BsRenderable.h"
 #include "CmMaterial.h"
 #include "CmMesh.h"
@@ -33,7 +32,7 @@ namespace BansheeEngine
 
 	void ForwardRenderer::renderAll() 
 	{
-		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
+		RenderContext& renderContext = gMainRC();
 
 		const vector<HCamera>::type& allCameras = gSceneManager().getAllCameras();
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
@@ -46,7 +45,7 @@ namespace BansheeEngine
 				RenderTargetPtr rt = vp->getTarget();
 
 				if(rt != nullptr)
-					renderContext->swapBuffers(rt); // TODO - This is wrong as potentially multiple viewports can share a single render target, and swap shouldn't
+					renderContext.swapBuffers(rt); // TODO - This is wrong as potentially multiple viewports can share a single render target, and swap shouldn't
 				// be done for every one of them
 			}
 		}
@@ -56,17 +55,17 @@ namespace BansheeEngine
 	{
 		vector<HRenderable>::type allRenderables = gSceneManager().getVisibleRenderables(camera);
 
-		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
-		renderContext->setViewport(camera->getViewport());
+		RenderContext& renderContext = gMainRC();
+		renderContext.setViewport(camera->getViewport());
 
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
-		renderContext->clear(camera->getViewport()->getTarget(), FBT_COLOR | FBT_DEPTH, Color::Blue);
+		renderContext.clear(camera->getViewport()->getTarget(), FBT_COLOR | FBT_DEPTH, Color::Blue);
 
-		renderContext->beginFrame();
+		renderContext.beginFrame();
 
 		// TODO - sort renderables by material/pass/parameters to minimize state changes
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
@@ -94,14 +93,14 @@ namespace BansheeEngine
 				PassParametersPtr paramsPtr = material->getPassParameters(i);
 				pass->bindParameters(renderContext, paramsPtr);
 
-				renderContext->render(mesh->getRenderOperation());
+				renderContext.render(mesh->getRenderOperation());
 			}
 		}
 
 		// Render overlays for this camera
 		OverlayManager::instance().render(camera.get(), renderContext);
 
-		renderContext->endFrame();
+		renderContext.endFrame();
 
 		// TODO - Sort renderables
 		// Render them

+ 1 - 0
CamelotCore/CamelotCore.vcxproj

@@ -176,6 +176,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="Include\CmDeferredRenderContextFwd.h" />
     <ClInclude Include="Include\CmGameObjectHandle.h" />
     <ClInclude Include="Include\CmGameObject.h" />
     <ClInclude Include="Include\CmGameObjectRTTI.h" />

+ 3 - 0
CamelotCore/CamelotCore.vcxproj.filters

@@ -438,6 +438,9 @@
     <ClInclude Include="Include\CmGpuResourceDataRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmDeferredRenderContextFwd.h">
+      <Filter>Header Files\RenderSystem</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">

+ 22 - 4
CamelotCore/Include/CmApplication.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "CmPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmHighLevelGpuProgram.h"
 #include "CmRenderWindow.h"
 
@@ -62,9 +63,6 @@ namespace CamelotFramework
 
 			RenderWindowPtr getPrimaryRenderWindow() const { return mPrimaryRenderWindow; }
 
-			// TODO: This is just for debug purposes. Normally I'd want to have one render context per scene view, not one global one
-			DeferredRenderContextPtr getPrimaryRenderContext() const { return mPrimaryRenderContext; }
-
 			/**
 			 * @brief	Loads a plugin.
 			 *
@@ -73,8 +71,12 @@ namespace CamelotFramework
 			void* loadPlugin(const String& pluginName);
 
 	private:
+		friend CM_EXPORT RenderContext& gMainRC();
+		friend CM_EXPORT SyncedRenderContext& gMainSyncedRC();
+
 		RenderWindowPtr mPrimaryRenderWindow;
-		DeferredRenderContextPtr mPrimaryRenderContext;
+		RenderContextPtr mPrimaryRenderContext;
+		SyncedRenderContext* mPrimarySyncedRenderContext;
 
 		bool mIsFrameRenderingFinished;
 		CM_MUTEX(mFrameRenderingFinishedMutex);
@@ -93,4 +95,20 @@ namespace CamelotFramework
 	};
 
 	CM_EXPORT Application& gApplication();
+
+	/**
+	 * @brief	A shortcut for accessing the primary render context. This render context may only be accessed safely
+	 * 			from the main thread.
+	 */
+	CM_EXPORT RenderContext& gMainRC();
+
+	/**
+	 * @brief	A shortcut for accessing the primary synchronized render context. This context may be accessed
+	 * 			from all threads except the render thread. All operations from this context will be executed after
+	 * 			non-synchronized primary context has finished executing.
+	 * 			
+	 * @note	It is more efficient to create your own non-synchronized render context if you plan on using the render context from
+	 * 			threads other than main often.
+	 */
+	CM_EXPORT SyncedRenderContext& gMainSyncedRC();
 }

+ 170 - 60
CamelotCore/Include/CmCommandQueue.h

@@ -8,43 +8,82 @@
 
 namespace CamelotFramework
 {
-	/**
-	 * @brief	Contains a list of commands that can be queued by one thread,
-	 * 			and executed by another.
-	 */
-	class CM_EXPORT CommandQueue
+	class CM_EXPORT CommandQueueNoSync
+	{
+	public:
+		CommandQueueNoSync() {}
+		virtual ~CommandQueueNoSync() {}
+
+		void lock() 
+		{
+		};
+
+		void unlock()
+		{
+		}
+
+	};
+
+	class CM_EXPORT CommandQueueSync
 	{
 	public:
-		struct Command
+		CommandQueueSync()
+			:mLock(mCommandQueueMutex, boost::defer_lock)
+		{ }
+		virtual ~CommandQueueSync() {}
+
+		void lock() 
+		{
+			mLock.lock();
+		};
+
+		void unlock()
 		{
+			mLock.unlock();
+		}
+
+	private:
+		CM_MUTEX(mCommandQueueMutex);
+		CM_LOCK_TYPE mLock;
+	};
+
+	struct QueuedCommand
+	{
 #ifdef CM_DEBUG_MODE
-			Command(boost::function<void(AsyncOp&)> _callback, UINT32 _debugId, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
-				:callbackWithReturnValue(_callback), debugId(_debugId), returnsValue(true), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
-			{ }
+		QueuedCommand(boost::function<void(AsyncOp&)> _callback, UINT32 _debugId, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+			:callbackWithReturnValue(_callback), debugId(_debugId), returnsValue(true), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
+		{ }
 
-			Command(boost::function<void()> _callback, UINT32 _debugId, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
-				:callback(_callback), debugId(_debugId), returnsValue(false), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
-			{ }
+		QueuedCommand(boost::function<void()> _callback, UINT32 _debugId, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+			:callback(_callback), debugId(_debugId), returnsValue(false), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
+		{ }
 
-			UINT32 debugId;
+		UINT32 debugId;
 #else
-			Command(boost::function<void(AsyncOp&)> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
-				:callbackWithReturnValue(_callback), returnsValue(true), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
-			{ }
+		QueuedCommand(boost::function<void(AsyncOp&)> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+			:callbackWithReturnValue(_callback), returnsValue(true), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
+		{ }
 
-			Command(boost::function<void()> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
-				:callback(_callback), returnsValue(false), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
-			{ }
+		QueuedCommand(boost::function<void()> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+			:callback(_callback), returnsValue(false), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
+		{ }
 #endif
 
-			boost::function<void()> callback;
-			boost::function<void(AsyncOp&)> callbackWithReturnValue;
-			AsyncOp asyncOp;
-			bool returnsValue;
-			UINT32 callbackId;
-			bool notifyWhenComplete;
-		};
+		boost::function<void()> callback;
+		boost::function<void(AsyncOp&)> callbackWithReturnValue;
+		AsyncOp asyncOp;
+		bool returnsValue;
+		UINT32 callbackId;
+		bool notifyWhenComplete;
+	};
 
+	/**
+	 * @brief	Contains a list of commands that can be queued by one thread,
+	 * 			and executed by another.
+	 */
+	class CM_EXPORT CommandQueueBase
+	{
+	public:
 		/**
 		 * @brief	Constructor.
 		 *
@@ -57,11 +96,38 @@ namespace CamelotFramework
 		 *							and also make sure you sync access to the queue properly.
 		 *							
 		 */
-		CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads = false);
-		~CommandQueue();
+		CommandQueueBase(CM_THREAD_ID_TYPE threadId, bool allowAllThreads = false);
+		virtual ~CommandQueueBase();
 
 		CM_THREAD_ID_TYPE getThreadId() const { return mMyThreadId; }
 
+		/**
+		 * @brief	Plays all provided commands. To get the commands call flush().
+		 *
+		 * @param	notifyCallback  	Callback that will be called if a command that has "notifyOnComplete" flag set.
+		 * 								The callback will receive "callbackId" of the command.
+		 */
+		void playback(std::queue<QueuedCommand>* commands, boost::function<void(UINT32)> notifyCallback);
+
+		/**
+		 * @brief	Plays all provided commands. To get the commands call flush().
+		 */
+		void playback(std::queue<QueuedCommand>* commands);
+
+		/**
+		 * @brief	Allows you to set a breakpoint that will trigger when the specified command is executed.
+		 * 			
+		 * @note	This is helpful when you receive an error on the executing thread and you cannot tell from where was
+		 * 			the command that caused the error queued from. However you can make a note of the queue and command index
+		 * 			and set a breakpoint so that it gets triggered next time you run the program. At that point you can know 
+		 * 			exactly which part of code queued the command by examining the stack trace.
+		 *
+		 * @param	queueIdx  	Zero-based index of the queue the command was queued on.
+		 * @param	commandIdx	Zero-based index of the command.
+		 */
+		static void addBreakpoint(UINT32 queueIdx, UINT32 commandIdx);
+
+	protected:
 		/**
 		 * @brief	Queue up a new command to execute. Make sure the provided function has all of its
 		 * 			parameters properly bound. Last parameter must be unbound and of AsyncOp&amp; type.
@@ -98,55 +164,26 @@ namespace CamelotFramework
 
 		/**
 		 * @brief	Returns a copy of all queued commands and makes room for new ones. Must be called from the thread
-		 * 			that created the command queue. Returned commands MUST be passed to playbackCommands.
+		 * 			that created the command queue. Returned commands MUST be passed to "playback" method.
 		 */
-		std::queue<Command>* flush();
+		std::queue<QueuedCommand>* flush();
 
 		/**
 		 * @brief	Cancels all currently queued commands.
 		 */
 		void cancelAll();
 
-		/**
-		 * @brief	Plays all provided commands. Should only be called from the render thread. To get the
-		 * 			commands call flushCommands().
-		 *
-		 * @param	notifyCallback  	Callback that will be called if a command that has "notifyOnComplete" flag set.
-		 * 								The callback will receive "callbackId" of the command.
-		 */
-		void playback(std::queue<Command>* commands, boost::function<void(UINT32)> notifyCallback);
-
-		/**
-		 * @brief	Plays all provided commands. Should only be called from the render thread. To get
-		 * 			the commands call flushCommands().
-		 */
-		void playback(std::queue<Command>* commands);
-
 		/**
 		 * @brief	Returns true if no commands are queued.
 		 */
 		bool isEmpty();
 
-		/**
-		 * @brief	Allows you to set a breakpoint that will trigger when the specified command is executed.
-		 * 			
-		 * @note	This is helpful when you receive an error on the executing thread and you cannot tell from where was
-		 * 			the command that caused the error queued from. However you can make a note of the queue and command index
-		 * 			and set a breakpoint so that it gets triggered next time you run the program. At that point you can know 
-		 * 			exactly which part of code queued the command by examining the stack trace.
-		 *
-		 * @param	queueIdx  	Zero-based index of the queue the command was queued on.
-		 * @param	commandIdx	Zero-based index of the command.
-		 */
-		static void addBreakpoint(UINT32 queueIdx, UINT32 commandIdx);
-
 	private:
-		std::queue<Command>* mCommands;
+		std::queue<QueuedCommand>* mCommands;
 
 		bool mAllowAllThreads;
 		
 		CM_THREAD_ID_TYPE mMyThreadId;
-		CM_MUTEX(mCommandBufferMutex);
 
 		// Various variables that allow for easier debugging by allowing us to trigger breakpoints
 		// when a certain command was queued.
@@ -185,4 +222,77 @@ namespace CamelotFramework
 		static void breakIfNeeded(UINT32 queueIdx, UINT32 commandIdx);
 #endif
 	};
+
+	/**
+	 * @copydoc CommandQueue
+	 */
+	template<class SyncPolicy = CommandQueueNoSync>
+	class CM_EXPORT CommandQueue : public CommandQueueBase, public SyncPolicy
+	{
+	public:
+		/**
+		 * @copydoc CommandQueueBase::CommandQueueBase
+		 */
+		CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads = false)
+			:CommandQueueBase(threadId, allowAllThreads)
+		{ }
+
+		~CommandQueue() {}
+
+		/**
+		 * @copydoc CommandQueueBase::queueReturn
+		 */
+		AsyncOp queueReturn(boost::function<void(AsyncOp&)> commandCallback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+		{
+			lock();
+			AsyncOp asyncOp = CommandQueueBase::queueReturn(commandCallback, _notifyWhenComplete, _callbackId);
+			unlock();
+
+			return asyncOp;
+		}
+
+		/**
+		 * @copydoc CommandQueueBase::queue
+		 */
+		void queue(boost::function<void()> commandCallback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+		{
+			lock();
+			CommandQueueBase::queue(commandCallback, _notifyWhenComplete, _callbackId);
+			unlock();
+		}
+
+		/**
+		 * @copydoc CommandQueueBase::flush
+		 */
+		std::queue<QueuedCommand>* flush()
+		{
+			lock();
+			std::queue<QueuedCommand>* commands = CommandQueueBase::flush();
+			unlock();
+
+			return commands;
+		}
+
+		/**
+		 * @copydoc CommandQueueBase::cancelAll
+		 */
+		void cancelAll()
+		{
+			lock();
+			CommandQueueBase::cancelAll();
+			unlock();
+		}
+
+		/**
+		 * @copydoc CommandQueueBase::isEmpty
+		 */
+		bool isEmpty()
+		{
+			lock();
+			bool empty = CommandQueueBase::isEmpty();
+			unlock();
+
+			return empty;
+		}
+	};
 }

+ 172 - 38
CamelotCore/Include/CmDeferredRenderContext.h

@@ -1,7 +1,10 @@
 #pragma once
 
 #include "CmPrerequisites.h"
+#include "CmDeferredRenderContextFwd.h"
 #include "CmCommonEnums.h"
+#include "CmRenderSystem.h"
+#include "CmCommandQueue.h"
 #include "CmSamplerState.h"
 #include "CmGpuProgram.h"
 #include "CmColor.h"
@@ -10,93 +13,205 @@ namespace CamelotFramework
 {
 	/**
 	 * @brief	Deferred render context allows you to execute RenderSystem commands outside of the render thread.
-	 * 			DeferredRenderContext cannot be shared between threads. It must be created and used on the threat that created it.
 	 * 			
 	 * @note	All commands are queued and only executed after the call to submitToGpu, in the order they were called.
 	 */
+	template <class CommandQueueSyncPolicy = CommandQueueNoSync>
 	class CM_EXPORT DeferredRenderContext
 	{
 	public:
-		DeferredRenderContext(RenderSystem* rs, CM_THREAD_ID_TYPE threadId);
-		~DeferredRenderContext();
+		/**
+		 * @brief	Constructor.
+		 *
+		 * @param	rs  			Render system to be used by the context.
+		 * @param	threadId		Identifier for the thread that created the context.
+		 * @param	syncedAccess	If false, the deferred render context can only be safely accessed from the thread that created it.
+		 * 							If true, deferred render context can be accessed from any thread safely, however there will be a slight performance
+		 * 							hit due to synchronization. In most cases you will want not to use synced access and instead create a separate context
+		 * 							for specific threads.
+		 */
+		DeferredRenderContext(RenderSystem* rs, CM_THREAD_ID_TYPE threadId)
+			:mRenderSystem(rs)
+		{
+			assert(mRenderSystem != nullptr);
+
+			mCommandQueue = CM_NEW(CommandQueue<CommandQueueSyncPolicy>, GenAlloc) CommandQueue<CommandQueueSyncPolicy>(threadId);
+		}
+
+		~DeferredRenderContext()
+		{
+			CM_DELETE(mCommandQueue, CommandQueue<CommandQueueSyncPolicy>, GenAlloc);
+		}
 
 		/** @copydoc RenderSystem::disableTextureUnit() */
-		void disableTextureUnit(GpuProgramType gptype, UINT16 texUnit);
+		void disableTextureUnit(GpuProgramType gptype, UINT16 texUnit)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::disableTextureUnit, mRenderSystem, gptype, texUnit));
+		}
 
 		/** @copydoc RenderSystem::setPointParameters() */
 		void setPointParameters(float size, bool attenuationEnabled, float constant, float linear, float quadratic, float minSize, float maxSize);
 
 		/** @copydoc RenderSystem::setTexture() */
-		void setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const TexturePtr &texPtr);
+		void setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const TexturePtr &texPtr)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setTexture, mRenderSystem, gptype, unit, enabled, texPtr));
+		}
 
 		/** @copydoc RenderSystem::setSamplerState() */
-		void setSamplerState(GpuProgramType gptype, UINT16 texUnit, const SamplerStatePtr& samplerState);
+		void setSamplerState(GpuProgramType gptype, UINT16 texUnit, const SamplerStatePtr& samplerState)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setSamplerState, mRenderSystem, gptype, texUnit, samplerState));
+		}
 
 		/** @copydoc RenderSystem::setBlendState() */
-		void setBlendState(const BlendStatePtr& blendState);
+		void setBlendState(const BlendStatePtr& blendState)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setBlendState, mRenderSystem, blendState));
+		}
 
 		/** @copydoc RenderSystem::setRasterizerState() */
-		void setRasterizerState(const RasterizerStatePtr& rasterizerState);
+		void setRasterizerState(const RasterizerStatePtr& rasterizerState)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setRasterizerState, mRenderSystem, rasterizerState));
+		}
 
 		/** @copydoc RenderSystem::setRasterizerState() */
-		void setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue);
+		void setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setDepthStencilState, mRenderSystem, depthStencilState, stencilRefValue));
+		}
 
 		/** @copydoc RenderSystem::setViewport() */
-		void setViewport(ViewportPtr& vp);
+		void setViewport(ViewportPtr& vp)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setViewport, mRenderSystem, vp));
+		}
 
 		/** @copydoc RenderSystem::setVertexBuffer() */
-		void setVertexBuffer(UINT32 index, const VertexBufferPtr& buffer);
+		void setVertexBuffer(UINT32 index, const VertexBufferPtr& buffer)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setVertexBuffer, mRenderSystem, index, buffer));
+		}
 
 		/** @copydoc RenderSystem::setIndexBuffer() */
-		void setIndexBuffer(const IndexBufferPtr& buffer);
+		void setIndexBuffer(const IndexBufferPtr& buffer)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setIndexBuffer, mRenderSystem, buffer));
+		}
 
 		/** @copydoc RenderSystem::setVertexDeclaration() */
-		void setVertexDeclaration(VertexDeclarationPtr vertexDeclaration);
+		void setVertexDeclaration(VertexDeclarationPtr vertexDeclaration)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setVertexDeclaration, mRenderSystem, vertexDeclaration));
+		}
 
 		/** @copydoc RenderSystem::setDrawOperation() */
-		void setDrawOperation(DrawOperationType op);
+		void setDrawOperation(DrawOperationType op)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setDrawOperation, mRenderSystem, op));
+		}
+
 
 		/** @copydoc RenderSystem::setClipPlanes() */
-		void setClipPlanes(const PlaneList& clipPlanes);
+		void setClipPlanes(const PlaneList& clipPlanes)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setClipPlanes, mRenderSystem, clipPlanes));
+		}
+
 		/** @copydoc RenderSystem::addClipPlane(const Plane&) */
-		void addClipPlane(const Plane& p);
+		void addClipPlane(const Plane& p)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::addClipPlane, mRenderSystem, p));
+		}
+
 		/** @copydoc RenderSystem::addClipPlane(float, float, float, float) */
-		void addClipPlane(float A, float B, float C, float D);
+		void addClipPlane(float A, float B, float C, float D)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::addClipPlane, mRenderSystem, A, B, C, D));
+		}
+
 		/** @copydoc RenderSystem::resetClipPlanes() */
-		void resetClipPlanes();
+		void resetClipPlanes()
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::resetClipPlanes, mRenderSystem));
+		}
 
 		/** @copydoc RenderSystem::setScissorTest() */
-		void setScissorTest(UINT32 left = 0, UINT32 top = 0, UINT32 right = 800, UINT32 bottom = 600);
+		void setScissorTest(UINT32 left = 0, UINT32 top = 0, UINT32 right = 800, UINT32 bottom = 600)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setScissorRect, mRenderSystem, left, top, right, bottom));
+		}
+
 
 		/** @copydoc RenderSystem::setRenderTarget() */
-		void setRenderTarget(RenderTargetPtr target);
+		void setRenderTarget(RenderTargetPtr target)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setRenderTarget, mRenderSystem, target));
+		}
 
 		/** @copydoc RenderSystem::bindGpuProgram() */
-		void bindGpuProgram(HGpuProgram prg);
+		void bindGpuProgram(HGpuProgram prg)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::bindGpuProgram, mRenderSystem, prg));
+		}
+
 		/** @copydoc RenderSystem::unbindGpuProgram() */
-		void unbindGpuProgram(GpuProgramType gptype);
+		void unbindGpuProgram(GpuProgramType gptype)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::unbindGpuProgram, mRenderSystem, gptype));
+		}
+
 		/** @copydoc RenderSystem::bindGpuParams() */
-		void bindGpuParams(GpuProgramType gptype, BindableGpuParams& params);
+		void bindGpuParams(GpuProgramType gptype, BindableGpuParams& params)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::bindGpuParams, mRenderSystem, gptype, params));
+		}
+
 
 		/** @copydoc RenderSystem::beginFrame() */
-		void beginFrame(void);
+		void beginFrame(void)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::beginFrame, mRenderSystem));
+		}
+
 		/** @copydoc RenderSystem::endFrame() */
-		void endFrame(void);
+		void endFrame(void)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::endFrame, mRenderSystem));
+		}
+
+		/** @copydoc RenderSystem::clear() */
+		void clear(RenderTargetPtr target, unsigned int buffers, const Color& color = Color::Black, float depth = 1.0f, unsigned short stencil = 0)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::clear, mRenderSystem, target, buffers, color, depth, stencil));
+		}
+
+		/** @copydoc RenderSystem::swapBuffers() */
+		void swapBuffers(RenderTargetPtr target)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::swapBuffers, mRenderSystem, target));
+		}
+
 
 		/** @copydoc RenderSystem::render() */
-		void render(const RenderOperation& op);
+		void render(const RenderOperation& op)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::render, mRenderSystem, op));
+		}
 
 		/** @copydoc RenderSystem::draw() */
-		void draw(UINT32 vertexCount);
+		void draw(UINT32 vertexCount)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::draw, mRenderSystem, vertexCount));
+		}
 
 		/** @copydoc RenderSystem::drawIndexed() */
-		void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexCount);
+		void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexCount)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::drawIndexed, mRenderSystem, startIndex, indexCount, vertexCount));
+		}
 
-		/** @copydoc RenderSystem::clear() */
-		void clear(RenderTargetPtr target, unsigned int buffers, const Color& color = Color::Black, float depth = 1.0f, unsigned short stencil = 0);
-
-		/** @copydoc RenderSystem::swapBuffers() */
-		void swapBuffers(RenderTargetPtr target);
 
 		/**
 		 * @copydoc RenderSystem::writeSubresource()
@@ -105,7 +220,12 @@ namespace CamelotFramework
 		 * 		 Until the async operation completes "data" is owned by the render thread and you won't
 		 * 		 be able to access it. 
 		 */
-		AsyncOp writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceData& data);
+		AsyncOp writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceData& data)
+		{
+			data.lock();
+
+			return mCommandQueue->queueReturn(boost::bind(&RenderSystem::writeSubresource, mRenderSystem, resource, subresourceIdx, boost::cref(data), _1));
+		}
 
 		/**
 		 * @copydoc RenderSystem::writeSubresource()
@@ -114,21 +234,35 @@ namespace CamelotFramework
 		 * 		 Until the async operation completes "data" is owned by the render thread and you won't
 		 * 		 be able to access it.
 		 */
-		AsyncOp readSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, GpuResourceData& data);
+		AsyncOp readSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, GpuResourceData& data)
+		{
+			data.lock();
+
+			return mCommandQueue->queueReturn(boost::bind(&RenderSystem::readSubresource, mRenderSystem, resource, subresourceIdx, boost::ref(data), _1));
+		}
 
 		/**
 		 * @brief	Makes all the currently queued commands available to the GPU. They will be executed
 		 * 			as soon as the render thread is ready.
 		 */
-		void submitToGpu();
+		void submitToGpu(bool blockUntilComplete = false)
+		{
+			std::queue<QueuedCommand>* commands = mCommandQueue->flush();
+
+			RenderSystem* rs = RenderSystem::instancePtr();
+			rs->queueCommand(boost::bind(&CommandQueueBase::playback, mCommandQueue, commands), blockUntilComplete);
+		}
 
 		/**
 		 * @brief	Cancels all commands in the queue.
 		 */
-		void cancelAll();
+		void cancelAll()
+		{
+			mCommandQueue->cancelAll();
+		}
 
 	private:
-		CommandQueue* mCommandQueue;
+		CommandQueue<CommandQueueSyncPolicy>* mCommandQueue;
 		RenderSystem* mRenderSystem;
 	};
 }

+ 15 - 0
CamelotCore/Include/CmDeferredRenderContextFwd.h

@@ -0,0 +1,15 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmCommandQueue.h"
+
+namespace CamelotFramework
+{	// TODO - This is duplicated here and in DeferredRenderContext
+	template<class T>
+	class DeferredRenderContext;
+
+	typedef DeferredRenderContext<CommandQueueNoSync> RenderContext;
+	typedef DeferredRenderContext<CommandQueueSync> SyncedRenderContext;
+	typedef std::shared_ptr<DeferredRenderContext<CommandQueueNoSync>> RenderContextPtr;
+	typedef std::shared_ptr<DeferredRenderContext<CommandQueueSync>> SyncedRenderContextPtr;
+}

+ 15 - 0
CamelotCore/Include/CmGpuResource.h

@@ -8,7 +8,22 @@ namespace CamelotFramework
 	class CM_EXPORT GpuResource : public Resource
 	{
 	public:
+		/**
+		 * @brief	Updates a part of the current resource with the provided data. Specific resource
+		 * 			implementations provide a way to retrieve a subresource index.
+		 * 			
+		 * @note	Call only from render thread.
+		 */
 		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data) = 0;
+
+		/**
+		 * @brief	Reads a part of the current resource into the provided "data" parameter.
+		 * 			Data buffer needs to be pre-allocated. Specific resource implementations 
+		 * 			provide a way to retrieve a subresource index and a way to allocate
+		 * 			the GpuResourceData buffer.
+		 * 			
+		 * @note	Call only from render thread.
+		 */
 		virtual void readSubresource(UINT32 subresourceIdx, GpuResourceData& data) = 0;
 
 		/************************************************************************/

+ 2 - 6
CamelotCore/Include/CmGpuResourceData.h

@@ -43,17 +43,13 @@ namespace CamelotFramework
 		 */
 		void setExternalBuffer(UINT8* data);
 
-	protected:
-		friend class DeferredRenderContext;
-		friend class RenderSystem;
-
 		/**
-		 * @brief	Locks the data and makes it available only to the render thread.
+		 * @brief	Locks the data and makes it available only to the render thread. Don't call manually.
 		 */
 		void lock() const;
 
 		/**
-		 * @brief	Unlocks the data and makes it available to all threads.
+		 * @brief	Unlocks the data and makes it available to all threads. Don't call manually.
 		 */
 		void unlock() const;
 

+ 3 - 2
CamelotCore/Include/CmPass.h

@@ -2,6 +2,7 @@
 
 #include "CmPrerequisites.h"
 #include "CmCommonEnums.h"
+#include "CmDeferredRenderContext.h"
 #include "CmColor.h"
 #include "CmIReflectable.h"
 
@@ -107,12 +108,12 @@ namespace CamelotFramework
 		/**
 		 * @brief	Makes this pass active. Anything rendered after this command will use this pass.
 		 */
-		void activate(DeferredRenderContextPtr& renderContext) const;
+		void activate(RenderContext& renderContext) const;
 
 		/**
 		 * @brief	Applies specified parameters to the active pass. 
 		 */
-		void bindParameters(DeferredRenderContextPtr& renderContext, const PassParametersPtr& params) const;
+		void bindParameters(RenderContext& renderContext, const PassParametersPtr& params) const;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 0 - 4
CamelotCore/Include/CmPrerequisites.h

@@ -124,14 +124,11 @@ namespace CamelotFramework {
 	class InputHandler;
 	class Renderer;
 	class RendererFactory;
-	class RenderCommandBuffer;
 	class WorkQueue;
 	class PassParameters;
 	class AsyncOp;
 	class HardwareBufferManager;
 	class FontManager;
-	class CommandQueue;
-	class DeferredRenderContext;
 	class DepthStencilState;
 	class RenderStateManager;
 	class RasterizerState;
@@ -204,7 +201,6 @@ namespace CamelotFramework
 	typedef std::shared_ptr<PassParameters> PassParametersPtr;
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<SceneObject> GameObjectPtr;
-	typedef std::shared_ptr<DeferredRenderContext> DeferredRenderContextPtr;
 	typedef std::shared_ptr<SamplerState> SamplerStatePtr;
 	typedef std::shared_ptr<DepthStencilState> DepthStencilStatePtr;
 	typedef std::shared_ptr<RasterizerState> RasterizerStatePtr;

+ 15 - 3
CamelotCore/Include/CmRenderSystem.h

@@ -38,6 +38,8 @@ THE SOFTWARE.
 #include "CmSamplerState.h"
 #include "CmCommonEnums.h"
 
+#include "CmCommandQueue.h"
+#include "CmDeferredRenderContextFwd.h"
 #include "CmRenderOperation.h"
 #include "CmRenderSystemCapabilities.h"
 #include "CmRenderTarget.h"
@@ -434,11 +436,13 @@ namespace CamelotFramework
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 
-		CommandQueue* mCommandQueue;
+		CommandQueue<CommandQueueNoSync>* mCommandQueue;
 
 		UINT32 mMaxCommandNotifyId; // ID that will be assigned to the next command with a notifier callback
 		vector<UINT32>::type mCommandsCompleted; // Completed commands that have notifier callbacks set up
 
+		SyncedRenderContext* mSyncedRenderContext;
+
 		/**
 		 * @brief	Initializes a separate render thread. Should only be called once.
 		 */
@@ -483,12 +487,20 @@ namespace CamelotFramework
 		CM_THREAD_ID_TYPE getRenderThreadId() const { return mRenderThreadId; }
 
 		/**
-		 * @brief	Creates a new render system context that you can use for rendering on 
+		 * @brief	Creates a new render system context that you can use for executing GPU commands from 
 		 * 			a non-render thread. You can have as many of these as you wish, the only limitation
 		 * 			is that you do not use a single instance on more than one thread. Each thread
 		 * 			requires its own context. The context will be bound to the thread you call this method on.
 		 */
-		DeferredRenderContextPtr createDeferredContext();
+		RenderContextPtr createDeferredContext();
+
+		/**
+		* @brief	Retrieves a context that may be used for rendering on the executing GPU commands from
+		* 			a non-render thread. There is only one synchronized context and you may access it from any thread you wish.
+		* 			Note however that it is much more efficient to create a separate non-synchronized context for each thread 
+		* 			you will be using it on.
+		 */
+		SyncedRenderContext& getSyncedDeferredContext();
 
 		/**
 		 * @brief	Queues a new command that will be added to the global command queue. You are allowed to call this from any thread,

+ 23 - 42
CamelotCore/Include/CmTexture.h

@@ -29,7 +29,7 @@ THE SOFTWARE.
 #define _Texture_H__
 
 #include "CmPrerequisites.h"
-#include "CmResource.h"
+#include "CmGpuResource.h"
 #include "CmHardwareBuffer.h"
 #include "CmPixelUtil.h"
 #include "CmTextureView.h"
@@ -85,7 +85,7 @@ namespace CamelotFramework {
             different in reality. Texture objects are created through
             the 'create' method of the TextureManager concrete subclass.
      */
-    class CM_EXPORT Texture : public Resource
+    class CM_EXPORT Texture : public GpuResource
     {
     public:
         /** Gets the type of texture 
@@ -138,59 +138,41 @@ namespace CamelotFramework {
         virtual UINT32 getNumFaces() const;
 
 		/**
-		 * @brief	Sets raw texture pixels for the specified mip level and texture face. Pixel format
-		 * 			must match the format of the texture.
-		 * 			
-		 * @note	Not-async. This operation will block the current thread until the render thread
-		 *			executes the command.
-		 */
-		void setRawPixels(const PixelData& data, UINT32 face = 0, UINT32 mip = 0);
-
-		/**
-		 * @brief	Sets raw texture pixels for the specified mip level and texture face. Pixel format
-		 * 			must match the format of the texture. Returns immediately
-		 * 			but the texture won't be updated until the command
-		 * 			executes on the render thread.
-		 * 			
-		 * @see		Texture::setRawPixels		
+		 * @copydoc GpuResource::writeSubresource
 		 */
-		void setRawPixels_async(const PixelData& data, UINT32 face = 0, UINT32 mip = 0);
+		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data);
 
 		/**
-		 * @brief	Internal version of Texture::setRawPixels. Only callable
-		 * 			from the render thread.
-		 *
-		 * @see		Texture::setRawPixels
+		 * @copydoc GpuResource::readSubresource
 		 */
-		virtual void setRawPixels_internal(const PixelData& data, UINT32 face = 0, UINT32 mip = 0);
+		virtual void readSubresource(UINT32 subresourceIdx, GpuResourceData& data);
 
 		/**
-		 * @brief	Gets raw pixels from the texture. This is a slow operation
-		 * 			as it will read data from the GPU. If the texture is compressed
-		 * 			the returned data will be contain compressed pixels as well.
+		 * @brief	Allocates a buffer you may use for storage when reading a subresource. You
+		 * 			need to allocate such a buffer if you are calling "readSubresource".
 		 * 			
-		 * @note	Not-async. This operation will block the current thread until the render thread
-		 *			executes the command.
+		 * @note	This method is thread safe.
 		 */
-		PixelDataPtr getRawPixels(UINT32 face = 0, UINT32 mip = 0);
-		
+		PixelDataPtr allocateSubresourceBuffer(UINT32 subresourceIdx) const;
 
 		/**
-		 * @brief	Async version of Texture::getRawPixels. Returns immediately
-		 * 			but you won't have access to the pixel data until the command
-		 * 			executes on the render thread.
-		 *
-		 * @see		Texture::getRawPixels
+		 * @brief	Maps a subresource index to an exact face and mip level. Subresource indexes
+		 * 			are used when reading or writing to the resource.
+		 * 			
+		 * @note	Subresource index is only valid for the instance it was created on. You cannot use a subresource
+		 * 			index from a different texture and expect to get valid result. Modifying the resource so the number
+		 * 			of subresources changes, invalidates all subresource indexes.
 		 */
-		AsyncOp getRawPixels_async(UINT32 face = 0, UINT32 mip = 0);
+		void mapFromSubresourceIdx(UINT32 subresourceIdx, UINT32& face, UINT32& mip) const;
 
 		/**
-		 * @brief	Internal version of Texture::getRawPixels. Only callable
-		 * 			from the render thread.
-		 *
-		 * @see		Texture::getRawPixels
+		 * @brief	Map a face and a mip level to a subresource index you can use for updating or reading
+		 * 			a specific sub-resource.
+		 * 			
+		 * @note	Generated subresource index is only valid for the instance it was created on. Modifying the resource so the number
+		 * 			of subresources changes, invalidates all subresource indexes.
 		 */
-		virtual void getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op);
+		UINT32 mapToSubresourceIdx(UINT32 face, UINT32 mip) const;
 
 		PixelData lock(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
 		void unlock();
@@ -256,7 +238,6 @@ namespace CamelotFramework {
 		virtual void unlockImpl() = 0;
 
 		virtual void copyImpl(TexturePtr& target) = 0;
-
 		/// @copydoc Resource::calculateSize
 		UINT32 calculateSize(void) const;
 

+ 16 - 3
CamelotCore/Include/CmTextureRTTI.h

@@ -5,6 +5,8 @@
 #include "CmTexture.h"
 #include "CmManagedDataBlock.h"
 #include "CmMath.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 // DEBUG ONLY
 #include "CmTextureManager.h"
@@ -32,7 +34,15 @@ namespace CamelotFramework
 			UINT32 face = (size_t)Math::Floor(idx / (float)(obj->getNumMipmaps() + 1));
 			UINT32 mipmap = idx % (obj->getNumMipmaps() + 1);
 
-			return obj->getRawPixels(face, mipmap);
+			UINT32 subresourceIdx = obj->mapToSubresourceIdx(face, mipmap);
+			PixelDataPtr pixelData = obj->allocateSubresourceBuffer(subresourceIdx);
+
+			GpuResourcePtr sharedTexPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
+
+			gMainSyncedRC().readSubresource(sharedTexPtr, subresourceIdx, *pixelData);
+			gMainSyncedRC().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
+
+			return pixelData;
 		}
 
 		void setPixelData(Texture* obj, UINT32 idx, PixelDataPtr data)
@@ -100,11 +110,14 @@ namespace CamelotFramework
 				UINT32 face = (size_t)Math::Floor(i / (float)(texture->getNumMipmaps() + 1));
 				UINT32 mipmap = i % (texture->getNumMipmaps() + 1);
 
-				PixelData data(*pixelData->at(i));
+				UINT32 subresourceIdx = texture->mapToSubresourceIdx(face, mipmap);
 
-				texture->setRawPixels(data, face, mipmap);
+				GpuResourcePtr sharedTexPtr = std::static_pointer_cast<GpuResource>(texture->getThisPtr());
+				gMainSyncedRC().writeSubresource(sharedTexPtr, subresourceIdx, *pixelData->at(i));
 			}
 
+			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+
 			CM_DELETE(pixelData, vector<PixelDataPtr>, PoolAlloc);
 			texture->mRTTIData = nullptr;	
 		}

+ 11 - 1
CamelotCore/Source/CmApplication.cpp

@@ -25,7 +25,6 @@
 #include "CmMaterialManager.h"
 #include "CmFontManager.h"
 #include "CmRenderer.h"
-#include "CmDeferredRenderContext.h"
 
 #include "CmMaterial.h"
 #include "CmShader.h"
@@ -60,6 +59,7 @@ namespace CamelotFramework
 		RenderSystem* renderSystem = RenderSystem::instancePtr();
 
 		mPrimaryRenderContext = renderSystem->createDeferredContext();
+		mPrimarySyncedRenderContext = &renderSystem->getSyncedDeferredContext();
 
 		SceneManager::startUp((SceneManager*)loadPlugin(desc.sceneManager));
 
@@ -204,4 +204,14 @@ namespace CamelotFramework
 		static Application application;
 		return application;
 	}
+
+	RenderContext& gMainRC()
+	{
+		return *gApplication().mPrimaryRenderContext.get();
+	}
+
+	SyncedRenderContext& gMainSyncedRC()
+	{
+		return *gApplication().mPrimarySyncedRenderContext;
+	}
 }

+ 52 - 57
CamelotCore/Source/CmCommandQueue.cpp

@@ -7,10 +7,10 @@
 namespace CamelotFramework
 {
 #if CM_DEBUG_MODE
-	CommandQueue::CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
+	CommandQueueBase::CommandQueueBase(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
 		:mMyThreadId(threadId), mAllowAllThreads(allowAllThreads), mMaxDebugIdx(0)
 	{
-		mCommands = CM_NEW(std::queue<Command>, PoolAlloc) std::queue<Command>();
+		mCommands = CM_NEW(std::queue<QueuedCommand>, PoolAlloc) std::queue<QueuedCommand>();
 
 		{
 			CM_LOCK_MUTEX(CommandQueueBreakpointMutex);
@@ -19,14 +19,14 @@ namespace CamelotFramework
 		}
 	}
 #else
-	CommandQueue::CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
+	CommandQueueBase::CommandQueueBase(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
 		:mMyThreadId(threadId), mAllowAllThreads(allowAllThreads)
 	{
-		mCommands = CM_NEW(std::queue<Command>, PoolAlloc) std::queue<Command>();
+		mCommands = CM_NEW(std::queue<QueuedCommand>, PoolAlloc) std::queue<QueuedCommand>();
 	}
 #endif
 
-	CommandQueue::~CommandQueue()
+	CommandQueueBase::~CommandQueueBase()
 	{
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
@@ -38,79 +38,74 @@ namespace CamelotFramework
 #endif
 
 		if(mCommands != nullptr)
-			CM_DELETE(mCommands, queue<Command>, PoolAlloc);
+			CM_DELETE(mCommands, queue<QueuedCommand>, PoolAlloc);
 	}
 
-	AsyncOp CommandQueue::queueReturn(boost::function<void(AsyncOp&)> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
+	AsyncOp CommandQueueBase::queueReturn(boost::function<void(AsyncOp&)> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
 	{
-#if CM_DEBUG_MODE
-#if CM_THREAD_SUPPORT != 0
-		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
-		{
-			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
-		}
-#endif
-#endif
+//#if CM_DEBUG_MODE
+//#if CM_THREAD_SUPPORT != 0
+//		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
+//		{
+//			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
+//		}
+//#endif
+//#endif
 
 #if CM_DEBUG_MODE
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 
-		Command newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
 #else
-		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 #endif
 
 		mCommands->push(newCommand);
 
 #if CM_FORCE_SINGLETHREADED_RENDERING
-		std::queue<CommandQueue::Command>* commands = flush();
+		std::queue<QueuedCommand>* commands = flush();
 		playback(commands);
 #endif
 
 		return newCommand.asyncOp;
 	}
 
-	void CommandQueue::queue(boost::function<void()> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
+	void CommandQueueBase::queue(boost::function<void()> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
 	{
-#if CM_DEBUG_MODE
-#if CM_THREAD_SUPPORT != 0
-		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
-		{
-			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
-		}
-#endif
-#endif
+//#if CM_DEBUG_MODE
+//#if CM_THREAD_SUPPORT != 0
+//		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
+//		{
+//			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
+//		}
+//#endif
+//#endif
 
 #if CM_DEBUG_MODE
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 
-		Command newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
 #else
-		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 #endif
 
 		mCommands->push(newCommand);
 
 #if CM_FORCE_SINGLETHREADED_RENDERING
-		std::queue<CommandQueue::Command>* commands = flush();
+		std::queue<QueuedCommand>* commands = flush();
 		playback(commands);
 #endif
 	}
 
-	std::queue<CommandQueue::Command>* CommandQueue::flush()
+	std::queue<QueuedCommand>* CommandQueueBase::flush()
 	{
-		std::queue<Command>* oldCommands = nullptr;
-		{
-			CM_LOCK_MUTEX(mCommandBufferMutex);
-
-			oldCommands = mCommands;
-			mCommands = CM_NEW(std::queue<Command>, PoolAlloc) std::queue<Command>();
-		}
+		std::queue<QueuedCommand>* oldCommands = mCommands;
+		mCommands = CM_NEW(std::queue<QueuedCommand>, PoolAlloc) std::queue<QueuedCommand>();
 
 		return oldCommands;
 	}
 
-	void CommandQueue::playback(std::queue<CommandQueue::Command>* commands, boost::function<void(UINT32)> notifyCallback)
+	void CommandQueueBase::playback(std::queue<QueuedCommand>* commands, boost::function<void(UINT32)> notifyCallback)
 	{
 #if CM_DEBUG_MODE
 		RenderSystem* rs = RenderSystem::instancePtr();
@@ -124,7 +119,7 @@ namespace CamelotFramework
 
 		while(!commands->empty())
 		{
-			Command& command = commands->front();
+			QueuedCommand& command = commands->front();
 
 			if(command.returnsValue)
 			{
@@ -150,24 +145,22 @@ namespace CamelotFramework
 			commands->pop();
 		}
 
-		CM_DELETE(commands, queue<Command>, PoolAlloc);
+		CM_DELETE(commands, queue<QueuedCommand>, PoolAlloc);
 	}
 
-	void CommandQueue::playback(std::queue<Command>* commands)
+	void CommandQueueBase::playback(std::queue<QueuedCommand>* commands)
 	{
 		playback(commands, boost::function<void(UINT32)>());
 	}
 
-	void CommandQueue::cancelAll()
+	void CommandQueueBase::cancelAll()
 	{
-		std::queue<CommandQueue::Command>* commands = flush();
-		CM_DELETE(commands, queue<Command>, PoolAlloc);
+		std::queue<QueuedCommand>* commands = flush();
+		CM_DELETE(commands, queue<QueuedCommand>, PoolAlloc);
 	}
 
-	bool CommandQueue::isEmpty()
+	bool CommandQueueBase::isEmpty()
 	{
-		CM_LOCK_MUTEX(mCommandBufferMutex);
-
 		if(mCommands != nullptr && mCommands->size() > 0)
 			return false;
 
@@ -175,12 +168,14 @@ namespace CamelotFramework
 	}
 
 #if CM_DEBUG_MODE
-	CM_STATIC_MUTEX_CLASS_INSTANCE(CommandQueueBreakpointMutex, CommandQueue);
-	UINT32 CommandQueue::MaxCommandQueueIdx = 0;
-	std::unordered_set<CommandQueue::QueueBreakpoint, CommandQueue::QueueBreakpoint::HashFunction, 
-		CommandQueue::QueueBreakpoint::EqualFunction> CommandQueue::SetBreakpoints;
+	CM_STATIC_MUTEX_CLASS_INSTANCE(CommandQueueBreakpointMutex, CommandQueueBase);
+
+	UINT32 CommandQueueBase::MaxCommandQueueIdx = 0;
+
+	std::unordered_set<CommandQueueBase::QueueBreakpoint, CommandQueueBase::QueueBreakpoint::HashFunction, 
+		CommandQueueBase::QueueBreakpoint::EqualFunction> CommandQueueBase::SetBreakpoints;
 
-	inline size_t CommandQueue::QueueBreakpoint::HashFunction::operator()(const QueueBreakpoint& v) const
+	inline size_t CommandQueueBase::QueueBreakpoint::HashFunction::operator()(const QueueBreakpoint& v) const
 	{
 		size_t seed = 0;
 		hash_combine(seed, v.queueIdx);
@@ -188,19 +183,19 @@ namespace CamelotFramework
 		return seed;
 	}
 
-	inline bool CommandQueue::QueueBreakpoint::EqualFunction::operator()(const QueueBreakpoint &a, const QueueBreakpoint &b) const
+	inline bool CommandQueueBase::QueueBreakpoint::EqualFunction::operator()(const QueueBreakpoint &a, const QueueBreakpoint &b) const
 	{
 		return a.queueIdx == b.queueIdx && a.commandIdx == b.commandIdx;
 	}
 
-	void CommandQueue::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
+	void CommandQueueBase::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
 	{
 		CM_LOCK_MUTEX(CommandQueueBreakpointMutex);
 
 		SetBreakpoints.insert(QueueBreakpoint(queueIdx, commandIdx));
 	}
 
-	void CommandQueue::breakIfNeeded(UINT32 queueIdx, UINT32 commandIdx)
+	void CommandQueueBase::breakIfNeeded(UINT32 queueIdx, UINT32 commandIdx)
 	{
 		// I purposely don't use a mutex here, as this gets called very often. Generally breakpoints
 		// will only be added at the start of the application, so race conditions should not occur.
@@ -212,7 +207,7 @@ namespace CamelotFramework
 		}
 	}
 #else
-	void CommandQueue::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
+	void CommandQueueBase::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
 	{
 		// Do nothing, no breakpoints in release
 	}

+ 0 - 172
CamelotCore/Source/CmDeferredRenderContext.cpp

@@ -9,177 +9,5 @@
 
 namespace CamelotFramework
 {
-	DeferredRenderContext::DeferredRenderContext(RenderSystem* rs, CM_THREAD_ID_TYPE threadId)
-		:mCommandQueue(CM_NEW(CommandQueue, GenAlloc) CommandQueue(threadId))
-		, mRenderSystem(rs)
-	{
-		assert(mRenderSystem != nullptr);
-	}
 
-	DeferredRenderContext::~DeferredRenderContext()
-	{
-		CM_DELETE(mCommandQueue, CommandQueue, GenAlloc);
-	}
-
-	void DeferredRenderContext::setViewport(ViewportPtr& vp)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setViewport, mRenderSystem, vp));
-	}
-
-	void DeferredRenderContext::setVertexBuffer(UINT32 index, const VertexBufferPtr& buffer)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setVertexBuffer, mRenderSystem, index, buffer));
-	}
-
-	void DeferredRenderContext::setIndexBuffer(const IndexBufferPtr& buffer)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setIndexBuffer, mRenderSystem, buffer));
-	}
-
-	void DeferredRenderContext::setVertexDeclaration(VertexDeclarationPtr vertexDeclaration)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setVertexDeclaration, mRenderSystem, vertexDeclaration));
-	}
-
-	void DeferredRenderContext::setDrawOperation(DrawOperationType op)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setDrawOperation, mRenderSystem, op));
-	}
-
-	void DeferredRenderContext::setSamplerState(GpuProgramType gptype, UINT16 texUnit, const SamplerStatePtr& samplerState)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setSamplerState, mRenderSystem, gptype, texUnit, samplerState));
-	}
-
-	void DeferredRenderContext::setBlendState(const BlendStatePtr& blendState)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setBlendState, mRenderSystem, blendState));
-	}
-
-	void DeferredRenderContext::setRasterizerState(const RasterizerStatePtr& rasterizerState)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setRasterizerState, mRenderSystem, rasterizerState));
-	}
-
-	void DeferredRenderContext::setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setDepthStencilState, mRenderSystem, depthStencilState, stencilRefValue));
-	}
-
-	void DeferredRenderContext::setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const TexturePtr& texPtr)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setTexture, mRenderSystem, gptype, unit, enabled, texPtr));
-	}
-
-	void DeferredRenderContext::disableTextureUnit(GpuProgramType gptype, UINT16 texUnit)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::disableTextureUnit, mRenderSystem, gptype, texUnit));
-	}
-
-	void DeferredRenderContext::setScissorTest(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setScissorRect, mRenderSystem, left, top, right, bottom));
-	}
-
-	void DeferredRenderContext::addClipPlane(const Plane &p)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::addClipPlane, mRenderSystem, p));
-	}
-
-	void DeferredRenderContext::addClipPlane(float A, float B, float C, float D)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::addClipPlane, mRenderSystem, A, B, C, D));
-	}
-
-	void DeferredRenderContext::setClipPlanes(const PlaneList& clipPlanes)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setClipPlanes, mRenderSystem, clipPlanes));
-	}
-
-	void DeferredRenderContext::resetClipPlanes()
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::resetClipPlanes, mRenderSystem));
-	}
-
-	void DeferredRenderContext::bindGpuProgram(HGpuProgram prg)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::bindGpuProgram, mRenderSystem, prg));
-	}
-
-	void DeferredRenderContext::unbindGpuProgram(GpuProgramType gptype)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::unbindGpuProgram, mRenderSystem, gptype));
-	}
-
-	void DeferredRenderContext::bindGpuParams(GpuProgramType gptype, BindableGpuParams& params)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::bindGpuParams, mRenderSystem, gptype, params));
-	}
-
-	void DeferredRenderContext::setRenderTarget(RenderTargetPtr target)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::setRenderTarget, mRenderSystem, target));
-	}
-
-	void DeferredRenderContext::clear(RenderTargetPtr target, unsigned int buffers, const Color& color, float depth, unsigned short stencil)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::clear, mRenderSystem, target, buffers, color, depth, stencil));
-	}
-
-	void DeferredRenderContext::beginFrame()
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::beginFrame, mRenderSystem));
-	}
-
-	void DeferredRenderContext::endFrame()
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::endFrame, mRenderSystem));
-	}
-
-	void DeferredRenderContext::swapBuffers(RenderTargetPtr target)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::swapBuffers, mRenderSystem, target));
-	}
-
-	void DeferredRenderContext::render(const RenderOperation& op)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::render, mRenderSystem, op));
-	}
-
-	void DeferredRenderContext::draw(UINT32 vertexCount)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::draw, mRenderSystem, vertexCount));
-	}
-
-	void DeferredRenderContext::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexCount)
-	{
-		mCommandQueue->queue(boost::bind(&RenderSystem::drawIndexed, mRenderSystem, startIndex, indexCount, vertexCount));
-	}
-
-	AsyncOp DeferredRenderContext::writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceData& data)
-	{
-		data.lock();
-
-		return mCommandQueue->queueReturn(boost::bind(&RenderSystem::writeSubresource, mRenderSystem, resource, subresourceIdx, boost::cref(data), _1));
-	}
-
-	AsyncOp DeferredRenderContext::readSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, GpuResourceData& data)
-	{
-		data.lock();
-
-		return mCommandQueue->queueReturn(boost::bind(&RenderSystem::readSubresource, mRenderSystem, resource, subresourceIdx, boost::ref(data), _1));
-	}
-
-	void DeferredRenderContext::submitToGpu()
-	{
-		std::queue<CommandQueue::Command>* commands = mCommandQueue->flush();
-
-		RenderSystem* rs = RenderSystem::instancePtr();
-		rs->queueCommand(boost::bind(&CommandQueue::playback, mCommandQueue, commands));
-	}
-
-	void DeferredRenderContext::cancelAll()
-	{
-		mCommandQueue->cancelAll();
-	}
 }

+ 24 - 25
CamelotCore/Source/CmPass.cpp

@@ -3,7 +3,6 @@
 #include "CmBlendState.h"
 #include "CmDepthStencilState.h"
 #include "CmPassRTTI.h"
-#include "CmDeferredRenderContext.h"
 #include "CmMaterial.h"
 #include "CmGpuParams.h"
 #include "CmException.h"
@@ -106,37 +105,37 @@ namespace CamelotFramework
 		return mStencilRefValue;
 	}
 	//----------------------------------------------------------------------
-	void Pass::activate(DeferredRenderContextPtr& renderContext) const
+	void Pass::activate(RenderContext& renderContext) const
 	{
 		HGpuProgram vertProgram = getVertexProgram();
 		if(vertProgram)
-			renderContext->bindGpuProgram(vertProgram);
+			renderContext.bindGpuProgram(vertProgram);
 		else
-			renderContext->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_VERTEX_PROGRAM);
 
 		HGpuProgram fragProgram = getFragmentProgram();
 		if(fragProgram)
-			renderContext->bindGpuProgram(fragProgram);
+			renderContext.bindGpuProgram(fragProgram);
 		else
-			renderContext->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 
 		HGpuProgram geomProgram = getGeometryProgram();
 		if(geomProgram)
-			renderContext->bindGpuProgram(geomProgram);
+			renderContext.bindGpuProgram(geomProgram);
 		else
-			renderContext->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 
 		HGpuProgram hullProgram = getHullProgram();
 		if(hullProgram)
-			renderContext->bindGpuProgram(hullProgram);
+			renderContext.bindGpuProgram(hullProgram);
 		else
-			renderContext->unbindGpuProgram(GPT_HULL_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_HULL_PROGRAM);
 
 		HGpuProgram domainProgram = getDomainProgram();
 		if(domainProgram)
-			renderContext->bindGpuProgram(domainProgram);
+			renderContext.bindGpuProgram(domainProgram);
 		else
-			renderContext->unbindGpuProgram(GPT_DOMAIN_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_DOMAIN_PROGRAM);
 
 		// TODO - Try to limit amount of state changes, if previous state is already the same (especially with textures)
 
@@ -146,48 +145,48 @@ namespace CamelotFramework
 		// Set up non-texture related pass settings
 		HBlendState blendState = getBlendState();
 		if(blendState != nullptr)
-			renderContext->setBlendState(blendState.getInternalPtr());
+			renderContext.setBlendState(blendState.getInternalPtr());
 		else
-			renderContext->setBlendState(BlendState::getDefault());
+			renderContext.setBlendState(BlendState::getDefault());
 
 		HDepthStencilState depthStancilState = getDepthStencilState();
 		if(depthStancilState != nullptr)
-			renderContext->setDepthStencilState(depthStancilState.getInternalPtr(), getStencilRefValue());
+			renderContext.setDepthStencilState(depthStancilState.getInternalPtr(), getStencilRefValue());
 		else
-			renderContext->setDepthStencilState(DepthStencilState::getDefault(), getStencilRefValue());
+			renderContext.setDepthStencilState(DepthStencilState::getDefault(), getStencilRefValue());
 
 		HRasterizerState rasterizerState = getRasterizerState();
 		if(rasterizerState != nullptr)
-			renderContext->setRasterizerState(rasterizerState.getInternalPtr());
+			renderContext.setRasterizerState(rasterizerState.getInternalPtr());
 		else
-			renderContext->setRasterizerState(RasterizerState::getDefault());
+			renderContext.setRasterizerState(RasterizerState::getDefault());
 	}
 	//----------------------------------------------------------------------
-	void Pass::bindParameters(DeferredRenderContextPtr& renderContext, const PassParametersPtr& params) const
+	void Pass::bindParameters(RenderContext& renderContext, const PassParametersPtr& params) const
 	{
 		HGpuProgram vertProgram = getVertexProgram();
 		if(vertProgram)
-			renderContext->bindGpuParams(GPT_VERTEX_PROGRAM, GpuParams::createBindableCopy(params->mVertParams));
+			renderContext.bindGpuParams(GPT_VERTEX_PROGRAM, GpuParams::createBindableCopy(params->mVertParams));
 
 		HGpuProgram fragProgram = getFragmentProgram();
 		if(fragProgram)
-			renderContext->bindGpuParams(GPT_FRAGMENT_PROGRAM, GpuParams::createBindableCopy(params->mFragParams));
+			renderContext.bindGpuParams(GPT_FRAGMENT_PROGRAM, GpuParams::createBindableCopy(params->mFragParams));
 
 		HGpuProgram geomProgram = getGeometryProgram();
 		if(geomProgram)
-			renderContext->bindGpuParams(GPT_GEOMETRY_PROGRAM, GpuParams::createBindableCopy(params->mGeomParams));
+			renderContext.bindGpuParams(GPT_GEOMETRY_PROGRAM, GpuParams::createBindableCopy(params->mGeomParams));
 
 		HGpuProgram hullProgram = getHullProgram();
 		if(hullProgram)
-			renderContext->bindGpuParams(GPT_HULL_PROGRAM, GpuParams::createBindableCopy(params->mHullParams));
+			renderContext.bindGpuParams(GPT_HULL_PROGRAM, GpuParams::createBindableCopy(params->mHullParams));
 
 		HGpuProgram domainProgram = getDomainProgram();
 		if(domainProgram)
-			renderContext->bindGpuParams(GPT_DOMAIN_PROGRAM, GpuParams::createBindableCopy(params->mDomainParams));
+			renderContext.bindGpuParams(GPT_DOMAIN_PROGRAM, GpuParams::createBindableCopy(params->mDomainParams));
 
 		HGpuProgram computeProgram = getComputeProgram();
 		if(computeProgram)
-			renderContext->bindGpuParams(GPT_COMPUTE_PROGRAM, GpuParams::createBindableCopy(params->mComputeParams));
+			renderContext.bindGpuParams(GPT_COMPUTE_PROGRAM, GpuParams::createBindableCopy(params->mComputeParams));
 	}
 	//----------------------------------------------------------------------
 	RTTITypeBase* Pass::getRTTIStatic()

+ 22 - 8
CamelotCore/Source/CmRenderSystem.cpp

@@ -33,14 +33,13 @@ THE SOFTWARE.
 
 #include "CmRenderSystem.h"
 
+#include "CmDeferredRenderContext.h"
 #include "CmViewport.h"
 #include "CmException.h"
 #include "CmRenderTarget.h"
 #include "CmRenderWindow.h"
 #include "CmPixelBuffer.h"
 #include "CmOcclusionQuery.h"
-#include "CmCommandQueue.h"
-#include "CmDeferredRenderContext.h"
 #include "CmGpuResource.h"
 #include "boost/bind.hpp"
 
@@ -68,6 +67,7 @@ namespace CamelotFramework {
 		, mRenderThreadShutdown(false)
 		, mCommandQueue(nullptr)
 		, mMaxCommandNotifyId(0)
+		, mSyncedRenderContext(nullptr)
     {
     }
 
@@ -80,7 +80,7 @@ namespace CamelotFramework {
 
 		if(mCommandQueue != nullptr)
 		{
-			CM_DELETE(mCommandQueue, CommandQueue, GenAlloc);
+			CM_DELETE(mCommandQueue, CommandQueue<CommandQueueNoSync>, GenAlloc);
 			mCommandQueue = nullptr;
 		}
 
@@ -91,7 +91,7 @@ namespace CamelotFramework {
 	RenderWindowPtr RenderSystem::initialize(const RENDER_WINDOW_DESC& primaryWindowDesc)
 	{
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
-		mCommandQueue = CM_NEW(CommandQueue, GenAlloc) CommandQueue(CM_THREAD_CURRENT_ID, true);
+		mCommandQueue = CM_NEW(CommandQueue<CommandQueueNoSync>, GenAlloc) CommandQueue<CommandQueueNoSync>(CM_THREAD_CURRENT_ID, true);
 		mPrimaryWindowDesc = primaryWindowDesc;
 
 		initRenderThread();
@@ -107,11 +107,18 @@ namespace CamelotFramework {
 		mVertexProgramBound = false;
 		mGeometryProgramBound = false;
 		mFragmentProgramBound = false;
+
+		mSyncedRenderContext = CM_NEW(DeferredRenderContext<CommandQueueSync>, GenAlloc) DeferredRenderContext<CommandQueueSync>(this, CM_THREAD_CURRENT_ID);
 	}
 
 	void RenderSystem::destroy_internal()
 	{
 		mActiveRenderTarget = nullptr;
+
+		if(mSyncedRenderContext != nullptr)
+		{
+			CM_DELETE(mSyncedRenderContext, DeferredRenderContext<CommandQueueSync>, GenAlloc);
+		}
 	}
 
 	const RenderSystemCapabilities* RenderSystem::getCapabilities(void) const 
@@ -273,6 +280,7 @@ namespace CamelotFramework {
 		THROW_IF_NOT_RENDER_THREAD;
 
 		resource->writeSubresource(subresourceIdx, data);
+		data.unlock();
 		asyncOp.completeOperation();
 	}
 
@@ -281,6 +289,7 @@ namespace CamelotFramework {
 		THROW_IF_NOT_RENDER_THREAD;
 
 		resource->readSubresource(subresourceIdx, data);
+		data.unlock();
 		asyncOp.completeOperation();
 	}
 
@@ -324,7 +333,7 @@ namespace CamelotFramework {
 		while(true)
 		{
 			// Wait until we get some ready commands
-			std::queue<CommandQueue::Command>* commands = nullptr;
+			std::queue<QueuedCommand>* commands = nullptr;
 			{
 				CM_LOCK_MUTEX_NAMED(mCommandQueueMutex, lock)
 
@@ -373,10 +382,15 @@ namespace CamelotFramework {
 		mRenderThreadStarted = false;
 	}
 
-	DeferredRenderContextPtr RenderSystem::createDeferredContext()
+	RenderContextPtr RenderSystem::createDeferredContext()
+	{
+		return RenderContextPtr(CM_NEW(DeferredRenderContext<CommandQueueNoSync>, GenAlloc) DeferredRenderContext<CommandQueueNoSync>(this, CM_THREAD_CURRENT_ID), 
+			&MemAllocDeleter<DeferredRenderContext<CommandQueueNoSync>, GenAlloc>::deleter);
+	}
+
+	SyncedRenderContext& RenderSystem::getSyncedDeferredContext()
 	{
-		return DeferredRenderContextPtr(CM_NEW(DeferredRenderContext, GenAlloc) DeferredRenderContext(this, CM_THREAD_CURRENT_ID), 
-			&MemAllocDeleter<DeferredRenderContext, GenAlloc>::deleter);
+		return *mSyncedRenderContext;
 	}
 	
 	AsyncOp RenderSystem::queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete)

+ 47 - 31
CamelotCore/Source/CmTexture.cpp

@@ -91,37 +91,54 @@ namespace CamelotFramework {
 		return getTextureType() == TEX_TYPE_CUBE_MAP ? 6 : 1;
 	}
 
-	void Texture::setRawPixels(const PixelData& data, UINT32 face, UINT32 mip)
+	void Texture::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
 	{
-		RenderSystem::instancePtr()->queueCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip), true);
-	}
+		if(data.getTypeId() != TID_PixelData)
+			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 
-	void Texture::setRawPixels_async(const PixelData& data, UINT32 face, UINT32 mip)
-	{
-		RenderSystem::instancePtr()->queueCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip));
-	}
+		const PixelData& pixelData = static_cast<const PixelData&>(data);
+
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mapFromSubresourceIdx(subresourceIdx, face, mip);
 
-	void Texture::setRawPixels_internal(const PixelData& data, UINT32 face, UINT32 mip)
-	{
 		PixelData myData = lock(GBL_WRITE_ONLY_DISCARD, mip, face);
-		PixelUtil::bulkPixelConversion(data, myData);
+		PixelUtil::bulkPixelConversion(pixelData, myData);
 		unlock();
 	}
 
-	PixelDataPtr Texture::getRawPixels(UINT32 face, UINT32 mip)
+	void Texture::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
 	{
-		AsyncOp op = RenderSystem::instancePtr()->queueReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1), true);
+		if(data.getTypeId() != TID_PixelData)
+			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 
-		return op.getReturnValue<PixelDataPtr>();
-	}
+		PixelData& pixelData = static_cast<PixelData&>(data);
 
-	AsyncOp Texture::getRawPixels_async(UINT32 face, UINT32 mip)
-	{
-		return RenderSystem::instancePtr()->queueReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1));
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mapFromSubresourceIdx(subresourceIdx, face, mip);
+
+		PixelData myData = lock(GBL_READ_ONLY, mip, face);
+
+#if CM_DEBUG_MODE
+		if(pixelData.getConsecutiveSize() != myData.getConsecutiveSize())
+		{
+			unlock();
+			CM_EXCEPT(InternalErrorException, "Buffer sizes don't match");
+		}
+#endif
+
+		PixelUtil::bulkPixelConversion(myData, pixelData);
+
+		unlock();
 	}
 
-	void Texture::getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op)
+	PixelDataPtr Texture::allocateSubresourceBuffer(UINT32 subresourceIdx) const
 	{
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mapFromSubresourceIdx(subresourceIdx, face, mip);
+
 		UINT32 numMips = getNumMipmaps();
 		UINT32 width = getWidth();
 		UINT32 height = getHeight();
@@ -142,24 +159,23 @@ namespace CamelotFramework {
 			&MemAllocDeleter<PixelData, PoolAlloc>::deleter);
 
 		dst->allocateInternalBuffer(totalSize);
-		UINT8* buffer = (UINT8*)dst->getData();
-
-		PixelData myData = lock(GBL_READ_ONLY, mip, face);
 
-#if CM_DEBUG_MODE
-		if(dst->getConsecutiveSize() != myData.getConsecutiveSize())
-		{
-			unlock();
-			CM_EXCEPT(InternalErrorException, "Buffer sizes don't match");
-		}
-#endif
+		return dst;
+	}
 
-		PixelUtil::bulkPixelConversion(myData, *dst);
+	void Texture::mapFromSubresourceIdx(UINT32 subresourceIdx, UINT32& face, UINT32& mip) const
+	{
+		UINT32 numMipmaps = getNumMipmaps() + 1;
 
-		unlock();
+		face = Math::FloorToInt((subresourceIdx) / (float)numMipmaps);
+		mip = subresourceIdx % numMipmaps;
+	}
 
-		op.completeOperation(dst);
+	UINT32 Texture::mapToSubresourceIdx(UINT32 face, UINT32 mip) const
+	{
+		return face * (getNumMipmaps() + 1) + mip;
 	}
+
 	//----------------------------------------------------------------------------
 	PixelData Texture::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{

+ 6 - 1
CamelotFontImporter/Source/CmFontImporter.cpp

@@ -5,6 +5,8 @@
 #include "CmResources.h"
 #include "CmDebug.h"
 #include "CmTexAtlasGenerator.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
@@ -240,7 +242,10 @@ namespace CamelotFramework
 
 				HTexture newTex = Texture::create(TEX_TYPE_2D, pageIter->width, pageIter->height, 0, PF_R8G8);
 				newTex.waitUntilLoaded();
-				newTex->setRawPixels(pixelData);
+
+				UINT32 subresourceIdx = newTex->mapToSubresourceIdx(0, 0);
+				gMainSyncedRC().writeSubresource(newTex.getInternalPtr(), subresourceIdx, pixelData);
+				gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 
 				fontData.texturePages.push_back(newTex);
 

+ 5 - 1
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -7,6 +7,8 @@
 #include "CmTextureManager.h"
 #include "CmTexture.h"
 #include "CmFileSystem.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 #include "FreeImage.h"
 
@@ -132,7 +134,9 @@ namespace CamelotFramework
 		{
 			PixelData src = imgData->getPixels(mip);
 
-			newTexture->setRawPixels(src, 0, mip);
+			UINT32 subresourceIdx = newTexture->mapToSubresourceIdx(0, mip);
+			gMainSyncedRC().writeSubresource(newTexture.getInternalPtr(), subresourceIdx, src);
+			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 		}
 
 		fileData->close();

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -160,6 +160,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="Source\CmAsyncOp.cpp" />
     <ClCompile Include="Source\CmBitmapWriter.cpp" />
     <ClCompile Include="Source\CmBox.cpp" />
     <ClCompile Include="Source\CmInt2.cpp" />

+ 6 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -46,6 +46,9 @@
     <Filter Include="Source Files\Debug">
       <UniqueIdentifier>{1f4518ad-c827-49dc-8e69-f99a37c82871}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Source Files\Threading">
+      <UniqueIdentifier>{cb0d2667-8d73-4d4c-9b2b-bc18fbd7fd70}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\CmTypes.h">
@@ -317,5 +320,8 @@
     <ClCompile Include="Source\CmBox.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmAsyncOp.cpp">
+      <Filter>Source Files\Threading</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 5 - 5
CamelotUtility/Include/CmAsyncOp.h

@@ -8,11 +8,11 @@ namespace CamelotFramework
 {
 	/**
 	 * @brief	Asynchronous operation. Contains uninitialized data until
-	 * 			isResolved returns true.
+	 * 			hasCompleted returns true.
 	 * 			
 	 * @note	You are allowed (and meant to) to copy this by value.
 	 */
-	class AsyncOp
+	class CM_UTILITY_EXPORT AsyncOp
 	{
 	private:
 		struct AsyncOpData
@@ -22,7 +22,7 @@ namespace CamelotFramework
 			{ }
 
 			boost::any mReturnValue;
-			bool mIsCompleted;
+			volatile bool mIsCompleted;
 		};
 
 	public:
@@ -38,12 +38,12 @@ namespace CamelotFramework
 		/**
 		 * @brief	Mark the async operation as completed.
 		 */
-		void completeOperation(boost::any returnValue) { mData->mReturnValue = returnValue; mData->mIsCompleted = true; }
+		void completeOperation(boost::any returnValue);
 
 		/**
 		 * @brief	Mark the async operation as completed, without setting a return value;
 		 */
-		void completeOperation() { mData->mIsCompleted = true; }
+		void completeOperation();
 
 		/**
 		 * @brief	Retrieves the value returned by the async operation.

+ 3 - 5
CamelotUtility/Include/CmMath.h

@@ -231,11 +231,6 @@ namespace CamelotFramework
         */
         ~Math();
 
-		static inline int IAbs (int iValue) { return ( iValue >= 0 ? iValue : -iValue ); }
-		static inline int ICeil (float fValue) { return int(ceil(fValue)); }
-		static inline int IFloor (float fValue) { return int(floor(fValue)); }
-        static int ISign (int iValue);
-
 		static inline float Abs (float fValue) { return float(fabs(fValue)); }
 		static inline Degree Abs (const Degree& dValue) { return Degree(fabs(dValue.valueDegrees())); }
 		static inline Radian Abs (const Radian& rValue) { return Radian(fabs(rValue.valueRadians())); }
@@ -244,6 +239,7 @@ namespace CamelotFramework
 		static inline Radian ATan (float fValue) { return Radian(atan(fValue)); }
 		static inline Radian ATan2 (float fY, float fX) { return Radian(atan2(fY,fX)); }
 		static inline float Ceil (float fValue) { return float(ceil(fValue)); }
+		static inline int CeilToInt (float fValue) { return int(ceil(fValue)); }
 		static inline bool isNaN(float f)
 		{
 			// std::isnan() is C99, not supported by all compilers
@@ -276,6 +272,8 @@ namespace CamelotFramework
 
 		static inline float Floor (float fValue) { return float(floor(fValue)); }
 
+		static inline int FloorToInt (float fValue) { return int(floor(fValue)); }
+
 		static inline float Log (float fValue) { return float(log(fValue)); }
 
 		/// Stored value of log(2) for frequent use

+ 2 - 0
CamelotUtility/Include/CmThreadDefines.h

@@ -46,6 +46,7 @@ THE SOFTWARE
 #define CM_STATIC_MUTEX_CLASS_INSTANCE(name, classTypeName) boost::recursive_mutex classTypeName##::name;
 #define CM_LOCK_MUTEX(name) boost::recursive_mutex::scoped_lock cmnameLock(name);
 #define CM_LOCK_MUTEX_NAMED(mutexName, lockName) boost::recursive_mutex::scoped_lock lockName(mutexName);
+#define CM_LOCK_TYPE boost::recursive_mutex::scoped_lock
 // like CM_AUTO_MUTEX but mutex held by pointer
 #define CM_AUTO_SHARED_MUTEX mutable boost::recursive_mutex *CM_AUTO_MUTEX_NAME;
 #define CM_LOCK_AUTO_SHARED_MUTEX assert(CM_AUTO_MUTEX_NAME); boost::recursive_mutex::scoped_lock cmAutoMutexLock(*CM_AUTO_MUTEX_NAME);
@@ -83,6 +84,7 @@ THE SOFTWARE
 #define CM_STATIC_MUTEX_CLASS_INSTANCE(name, classTypeName)
 #define CM_LOCK_MUTEX(name)
 #define CM_LOCK_MUTEX_NAMED(mutexName, lockName)
+#define CM_LOCK_TYPE UINT32
 #define CM_AUTO_SHARED_MUTEX
 #define CM_LOCK_AUTO_SHARED_MUTEX
 #define CM_COPY_AUTO_SHARED_MUTEX(from)

+ 15 - 0
CamelotUtility/Source/CmAsyncOp.cpp

@@ -0,0 +1,15 @@
+#include "CmAsyncOp.h"
+
+namespace CamelotFramework
+{
+	void AsyncOp::completeOperation(boost::any returnValue) 
+	{ 
+		mData->mReturnValue = returnValue; 
+		mData->mIsCompleted = true; 
+	}
+
+	void AsyncOp::completeOperation() 
+	{ 
+		mData->mIsCompleted = true; 
+	}
+}

+ 0 - 5
CamelotUtility/Source/CmMath.cpp

@@ -115,11 +115,6 @@ namespace CamelotFramework
 		return mTanTable[idx];
     }
     //-----------------------------------------------------------------------
-    int Math::ISign (int iValue)
-    {
-        return ( iValue > 0 ? +1 : ( iValue < 0 ? -1 : 0 ) );
-    }
-    //-----------------------------------------------------------------------
     Radian Math::ACos (float fValue)
     {
         if ( -1.0 < fValue )

+ 5 - 44
TODO.txt

@@ -9,54 +9,15 @@ When I'm canceling command queue commands I might be canceling important user co
    - input lag?
 
 <<<<<<<Resource update/read>>>>>>>>
-In order to get write/readSubresource usable I probably need to add AsyncOp.waitUntilComplete
- - (Also remove "blockUntilFinished" parameters when queuing commands, as waitUntilComplete can be used instead)
-   - Or can it? Some operations don't return AsyncOp
-DeferredContext
- - updateSubresource
- - readSubresource - how to avoid casting returned value to either MeshData or PixelData?
-   - Have it as a parameter, that is created on main thread, using the source resource. (e.g. Texture::createCPUBuffer)
+get rid of thread checks for synced contexts (currently theyre commented out)
+RenderSystem does syncing external to CommandQueue
+ - That probably won't be needed once I have syncable CommandQueue
 
-Remove PixelData::ownsData and instead use a shared_ptr for GpuResourceData. 
-Otherwise it gets very difficult handling the sharing of "mLocked" variable, and also PixelData creation.
-
-All data classes (MeshData, PixelData, etc) derive from GpuBufferData class. 
- - It contains basically just raw bytes.
- - It has lock/unlock methods (used mostly internally)
- - Upon submitting GpuBufferData to updateResource it gets locked so user cannot change it anymore
-
-QUESTION: How to deal with GpuBufferData for MeshData?
- - It updates two separate buffers
-
-QUESTION: How to implement readResource and have the user be able to accurately read the returned data via
- MeshData/PixelData?
-
-Inherit all buffer classes (texture, mesh, GPUBlock) from IGpuBuffer interface
-
-DeferredRenderContext::updateResource(IGpuBuffer, GpuBufferData)
-AsyncOp DeferredRenderContext::readResource(IGpuBuffer)
- - When Resources::save needs to save a resource how do I easily read the data!?
+MeshData needs to be ported to GpuResourceData format
+ - I don't want to give up the current MeshData interface as it's easy to use. Anything lower level and I might just be using vertex/index buffers directly
 
 --------
 
-Methods to port:
-WRITE:
- - setRawPixels
- - setRawPixels_async
- - setMeshData
- - GpuParamBlock::updateBuffer
- - RenderTarget::swapBuffers
-READ:
- - getMeshData
- - getRawPixels
- - getRawPixels_async
-
---------
-
-Start with just GpuParamBlock and then move to Mesh/Texture later
-
-
-
  - My test model is rendering back faces. I need to flip them.
   - Although more than likely I am loading the model incorrectly since it works in Unity?
   - I probably want to determine front faces based on normals