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
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "BsOverlay.h"
 #include "BsOverlay.h"
 #include "BsTextSprite.h"
 #include "BsTextSprite.h"
 #include "CmORect.h"
 #include "CmORect.h"
@@ -15,7 +16,7 @@ namespace BansheeEngine
 		void setSkin(const GUISkin* skin);
 		void setSkin(const GUISkin* skin);
 		const GUISkin* getGUISkin() const;
 		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:
 	protected:
 		friend class CM::SceneObject;
 		friend class CM::SceneObject;
 		friend class GUIElement;
 		friend class GUIElement;

+ 2 - 1
BansheeEngine/Include/BsOverlay.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmComponent.h"
 #include "CmComponent.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -16,7 +17,7 @@ namespace BansheeEngine
 	public:
 	public:
 		virtual ~Overlay();
 		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() {}
 		virtual void update() {}
 
 
 	protected:
 	protected:

+ 2 - 1
BansheeEngine/Include/BsOverlayManager.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmModule.h"
 #include "CmModule.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -16,7 +17,7 @@ namespace BansheeEngine
 	class BS_EXPORT OverlayManager : public CM::Module<OverlayManager>
 	class BS_EXPORT OverlayManager : public CM::Module<OverlayManager>
 	{
 	{
 	public:
 	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 attachOverlay(const Camera* camera, const Overlay* overlay);
 		void detachOverlay(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,
 		// 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.
 		// 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);
 				PassParametersPtr paramsPtr = material->getPassParameters(i);
 				pass->bindParameters(renderContext, paramsPtr);
 				pass->bindParameters(renderContext, paramsPtr);
 
 
-				renderContext->render(mesh->getRenderOperation());
+				renderContext.render(mesh->getRenderOperation());
 			}
 			}
 
 
 			meshIdx++;
 			meshIdx++;

+ 1 - 1
BansheeEngine/Source/BsOverlayManager.cpp

@@ -6,7 +6,7 @@ using namespace CamelotFramework;
 
 
 namespace BansheeEngine
 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);
 		auto overlays = mOverlaysPerCamera.find(camera);
 
 

+ 0 - 3
BansheeForwardRenderer/Include/BsForwardRenderer.h

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

+ 8 - 9
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -1,7 +1,6 @@
 #include "BsForwardRenderer.h"
 #include "BsForwardRenderer.h"
 #include "BsCamera.h"
 #include "BsCamera.h"
 #include "BsSceneManager.h"
 #include "BsSceneManager.h"
-#include "CmDeferredRenderContext.h"
 #include "BsRenderable.h"
 #include "BsRenderable.h"
 #include "CmMaterial.h"
 #include "CmMaterial.h"
 #include "CmMesh.h"
 #include "CmMesh.h"
@@ -33,7 +32,7 @@ namespace BansheeEngine
 
 
 	void ForwardRenderer::renderAll() 
 	void ForwardRenderer::renderAll() 
 	{
 	{
-		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
+		RenderContext& renderContext = gMainRC();
 
 
 		const vector<HCamera>::type& allCameras = gSceneManager().getAllCameras();
 		const vector<HCamera>::type& allCameras = gSceneManager().getAllCameras();
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
@@ -46,7 +45,7 @@ namespace BansheeEngine
 				RenderTargetPtr rt = vp->getTarget();
 				RenderTargetPtr rt = vp->getTarget();
 
 
 				if(rt != nullptr)
 				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
 				// be done for every one of them
 			}
 			}
 		}
 		}
@@ -56,17 +55,17 @@ namespace BansheeEngine
 	{
 	{
 		vector<HRenderable>::type allRenderables = gSceneManager().getVisibleRenderables(camera);
 		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 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 		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
 		// TODO - sort renderables by material/pass/parameters to minimize state changes
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
@@ -94,14 +93,14 @@ namespace BansheeEngine
 				PassParametersPtr paramsPtr = material->getPassParameters(i);
 				PassParametersPtr paramsPtr = material->getPassParameters(i);
 				pass->bindParameters(renderContext, paramsPtr);
 				pass->bindParameters(renderContext, paramsPtr);
 
 
-				renderContext->render(mesh->getRenderOperation());
+				renderContext.render(mesh->getRenderOperation());
 			}
 			}
 		}
 		}
 
 
 		// Render overlays for this camera
 		// Render overlays for this camera
 		OverlayManager::instance().render(camera.get(), renderContext);
 		OverlayManager::instance().render(camera.get(), renderContext);
 
 
-		renderContext->endFrame();
+		renderContext.endFrame();
 
 
 		// TODO - Sort renderables
 		// TODO - Sort renderables
 		// Render them
 		// Render them

+ 1 - 0
CamelotCore/CamelotCore.vcxproj

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

+ 3 - 0
CamelotCore/CamelotCore.vcxproj.filters

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

+ 22 - 4
CamelotCore/Include/CmApplication.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
+#include "CmDeferredRenderContext.h"
 #include "CmHighLevelGpuProgram.h"
 #include "CmHighLevelGpuProgram.h"
 #include "CmRenderWindow.h"
 #include "CmRenderWindow.h"
 
 
@@ -62,9 +63,6 @@ namespace CamelotFramework
 
 
 			RenderWindowPtr getPrimaryRenderWindow() const { return mPrimaryRenderWindow; }
 			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.
 			 * @brief	Loads a plugin.
 			 *
 			 *
@@ -73,8 +71,12 @@ namespace CamelotFramework
 			void* loadPlugin(const String& pluginName);
 			void* loadPlugin(const String& pluginName);
 
 
 	private:
 	private:
+		friend CM_EXPORT RenderContext& gMainRC();
+		friend CM_EXPORT SyncedRenderContext& gMainSyncedRC();
+
 		RenderWindowPtr mPrimaryRenderWindow;
 		RenderWindowPtr mPrimaryRenderWindow;
-		DeferredRenderContextPtr mPrimaryRenderContext;
+		RenderContextPtr mPrimaryRenderContext;
+		SyncedRenderContext* mPrimarySyncedRenderContext;
 
 
 		bool mIsFrameRenderingFinished;
 		bool mIsFrameRenderingFinished;
 		CM_MUTEX(mFrameRenderingFinishedMutex);
 		CM_MUTEX(mFrameRenderingFinishedMutex);
@@ -93,4 +95,20 @@ namespace CamelotFramework
 	};
 	};
 
 
 	CM_EXPORT Application& gApplication();
 	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
 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:
 	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
 #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
 #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
 #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.
 		 * @brief	Constructor.
 		 *
 		 *
@@ -57,11 +96,38 @@ namespace CamelotFramework
 		 *							and also make sure you sync access to the queue properly.
 		 *							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; }
 		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
 		 * @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.
 		 * 			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
 		 * @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.
 		 * @brief	Cancels all currently queued commands.
 		 */
 		 */
 		void cancelAll();
 		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.
 		 * @brief	Returns true if no commands are queued.
 		 */
 		 */
 		bool isEmpty();
 		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:
 	private:
-		std::queue<Command>* mCommands;
+		std::queue<QueuedCommand>* mCommands;
 
 
 		bool mAllowAllThreads;
 		bool mAllowAllThreads;
 		
 		
 		CM_THREAD_ID_TYPE mMyThreadId;
 		CM_THREAD_ID_TYPE mMyThreadId;
-		CM_MUTEX(mCommandBufferMutex);
 
 
 		// Various variables that allow for easier debugging by allowing us to trigger breakpoints
 		// Various variables that allow for easier debugging by allowing us to trigger breakpoints
 		// when a certain command was queued.
 		// when a certain command was queued.
@@ -185,4 +222,77 @@ namespace CamelotFramework
 		static void breakIfNeeded(UINT32 queueIdx, UINT32 commandIdx);
 		static void breakIfNeeded(UINT32 queueIdx, UINT32 commandIdx);
 #endif
 #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
 #pragma once
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
+#include "CmDeferredRenderContextFwd.h"
 #include "CmCommonEnums.h"
 #include "CmCommonEnums.h"
+#include "CmRenderSystem.h"
+#include "CmCommandQueue.h"
 #include "CmSamplerState.h"
 #include "CmSamplerState.h"
 #include "CmGpuProgram.h"
 #include "CmGpuProgram.h"
 #include "CmColor.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.
 	 * @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.
 	 * @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
 	class CM_EXPORT DeferredRenderContext
 	{
 	{
 	public:
 	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() */
 		/** @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() */
 		/** @copydoc RenderSystem::setPointParameters() */
 		void setPointParameters(float size, bool attenuationEnabled, float constant, float linear, float quadratic, float minSize, float maxSize);
 		void setPointParameters(float size, bool attenuationEnabled, float constant, float linear, float quadratic, float minSize, float maxSize);
 
 
 		/** @copydoc RenderSystem::setTexture() */
 		/** @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() */
 		/** @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() */
 		/** @copydoc RenderSystem::setBlendState() */
-		void setBlendState(const BlendStatePtr& blendState);
+		void setBlendState(const BlendStatePtr& blendState)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setBlendState, mRenderSystem, blendState));
+		}
 
 
 		/** @copydoc RenderSystem::setRasterizerState() */
 		/** @copydoc RenderSystem::setRasterizerState() */
-		void setRasterizerState(const RasterizerStatePtr& rasterizerState);
+		void setRasterizerState(const RasterizerStatePtr& rasterizerState)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setRasterizerState, mRenderSystem, rasterizerState));
+		}
 
 
 		/** @copydoc RenderSystem::setRasterizerState() */
 		/** @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() */
 		/** @copydoc RenderSystem::setViewport() */
-		void setViewport(ViewportPtr& vp);
+		void setViewport(ViewportPtr& vp)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setViewport, mRenderSystem, vp));
+		}
 
 
 		/** @copydoc RenderSystem::setVertexBuffer() */
 		/** @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() */
 		/** @copydoc RenderSystem::setIndexBuffer() */
-		void setIndexBuffer(const IndexBufferPtr& buffer);
+		void setIndexBuffer(const IndexBufferPtr& buffer)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setIndexBuffer, mRenderSystem, buffer));
+		}
 
 
 		/** @copydoc RenderSystem::setVertexDeclaration() */
 		/** @copydoc RenderSystem::setVertexDeclaration() */
-		void setVertexDeclaration(VertexDeclarationPtr vertexDeclaration);
+		void setVertexDeclaration(VertexDeclarationPtr vertexDeclaration)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setVertexDeclaration, mRenderSystem, vertexDeclaration));
+		}
 
 
 		/** @copydoc RenderSystem::setDrawOperation() */
 		/** @copydoc RenderSystem::setDrawOperation() */
-		void setDrawOperation(DrawOperationType op);
+		void setDrawOperation(DrawOperationType op)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setDrawOperation, mRenderSystem, op));
+		}
+
 
 
 		/** @copydoc RenderSystem::setClipPlanes() */
 		/** @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&) */
 		/** @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) */
 		/** @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() */
 		/** @copydoc RenderSystem::resetClipPlanes() */
-		void resetClipPlanes();
+		void resetClipPlanes()
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::resetClipPlanes, mRenderSystem));
+		}
 
 
 		/** @copydoc RenderSystem::setScissorTest() */
 		/** @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() */
 		/** @copydoc RenderSystem::setRenderTarget() */
-		void setRenderTarget(RenderTargetPtr target);
+		void setRenderTarget(RenderTargetPtr target)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::setRenderTarget, mRenderSystem, target));
+		}
 
 
 		/** @copydoc RenderSystem::bindGpuProgram() */
 		/** @copydoc RenderSystem::bindGpuProgram() */
-		void bindGpuProgram(HGpuProgram prg);
+		void bindGpuProgram(HGpuProgram prg)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::bindGpuProgram, mRenderSystem, prg));
+		}
+
 		/** @copydoc RenderSystem::unbindGpuProgram() */
 		/** @copydoc RenderSystem::unbindGpuProgram() */
-		void unbindGpuProgram(GpuProgramType gptype);
+		void unbindGpuProgram(GpuProgramType gptype)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::unbindGpuProgram, mRenderSystem, gptype));
+		}
+
 		/** @copydoc RenderSystem::bindGpuParams() */
 		/** @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() */
 		/** @copydoc RenderSystem::beginFrame() */
-		void beginFrame(void);
+		void beginFrame(void)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::beginFrame, mRenderSystem));
+		}
+
 		/** @copydoc RenderSystem::endFrame() */
 		/** @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() */
 		/** @copydoc RenderSystem::render() */
-		void render(const RenderOperation& op);
+		void render(const RenderOperation& op)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::render, mRenderSystem, op));
+		}
 
 
 		/** @copydoc RenderSystem::draw() */
 		/** @copydoc RenderSystem::draw() */
-		void draw(UINT32 vertexCount);
+		void draw(UINT32 vertexCount)
+		{
+			mCommandQueue->queue(boost::bind(&RenderSystem::draw, mRenderSystem, vertexCount));
+		}
 
 
 		/** @copydoc RenderSystem::drawIndexed() */
 		/** @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()
 		 * @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
 		 * 		 Until the async operation completes "data" is owned by the render thread and you won't
 		 * 		 be able to access it. 
 		 * 		 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()
 		 * @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
 		 * 		 Until the async operation completes "data" is owned by the render thread and you won't
 		 * 		 be able to access it.
 		 * 		 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
 		 * @brief	Makes all the currently queued commands available to the GPU. They will be executed
 		 * 			as soon as the render thread is ready.
 		 * 			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.
 		 * @brief	Cancels all commands in the queue.
 		 */
 		 */
-		void cancelAll();
+		void cancelAll()
+		{
+			mCommandQueue->cancelAll();
+		}
 
 
 	private:
 	private:
-		CommandQueue* mCommandQueue;
+		CommandQueue<CommandQueueSyncPolicy>* mCommandQueue;
 		RenderSystem* mRenderSystem;
 		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
 	class CM_EXPORT GpuResource : public Resource
 	{
 	{
 	public:
 	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;
 		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;
 		virtual void readSubresource(UINT32 subresourceIdx, GpuResourceData& data) = 0;
 
 
 		/************************************************************************/
 		/************************************************************************/

+ 2 - 6
CamelotCore/Include/CmGpuResourceData.h

@@ -43,17 +43,13 @@ namespace CamelotFramework
 		 */
 		 */
 		void setExternalBuffer(UINT8* data);
 		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;
 		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;
 		void unlock() const;
 
 

+ 3 - 2
CamelotCore/Include/CmPass.h

@@ -2,6 +2,7 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmCommonEnums.h"
 #include "CmCommonEnums.h"
+#include "CmDeferredRenderContext.h"
 #include "CmColor.h"
 #include "CmColor.h"
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
 
 
@@ -107,12 +108,12 @@ namespace CamelotFramework
 		/**
 		/**
 		 * @brief	Makes this pass active. Anything rendered after this command will use this pass.
 		 * @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. 
 		 * @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		                     		*/
 		/* 								RTTI		                     		*/

+ 0 - 4
CamelotCore/Include/CmPrerequisites.h

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

+ 15 - 3
CamelotCore/Include/CmRenderSystem.h

@@ -38,6 +38,8 @@ THE SOFTWARE.
 #include "CmSamplerState.h"
 #include "CmSamplerState.h"
 #include "CmCommonEnums.h"
 #include "CmCommonEnums.h"
 
 
+#include "CmCommandQueue.h"
+#include "CmDeferredRenderContextFwd.h"
 #include "CmRenderOperation.h"
 #include "CmRenderOperation.h"
 #include "CmRenderSystemCapabilities.h"
 #include "CmRenderSystemCapabilities.h"
 #include "CmRenderTarget.h"
 #include "CmRenderTarget.h"
@@ -434,11 +436,13 @@ namespace CamelotFramework
 		CM_THREAD_TYPE* mRenderThread;
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 #endif
 
 
-		CommandQueue* mCommandQueue;
+		CommandQueue<CommandQueueNoSync>* mCommandQueue;
 
 
 		UINT32 mMaxCommandNotifyId; // ID that will be assigned to the next command with a notifier callback
 		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
 		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.
 		 * @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; }
 		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
 		 * 			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
 		 * 			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.
 		 * 			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,
 		 * @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__
 #define _Texture_H__
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
-#include "CmResource.h"
+#include "CmGpuResource.h"
 #include "CmHardwareBuffer.h"
 #include "CmHardwareBuffer.h"
 #include "CmPixelUtil.h"
 #include "CmPixelUtil.h"
 #include "CmTextureView.h"
 #include "CmTextureView.h"
@@ -85,7 +85,7 @@ namespace CamelotFramework {
             different in reality. Texture objects are created through
             different in reality. Texture objects are created through
             the 'create' method of the TextureManager concrete subclass.
             the 'create' method of the TextureManager concrete subclass.
      */
      */
-    class CM_EXPORT Texture : public Resource
+    class CM_EXPORT Texture : public GpuResource
     {
     {
     public:
     public:
         /** Gets the type of texture 
         /** Gets the type of texture 
@@ -138,59 +138,41 @@ namespace CamelotFramework {
         virtual UINT32 getNumFaces() const;
         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);
 		PixelData lock(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
 		void unlock();
 		void unlock();
@@ -256,7 +238,6 @@ namespace CamelotFramework {
 		virtual void unlockImpl() = 0;
 		virtual void unlockImpl() = 0;
 
 
 		virtual void copyImpl(TexturePtr& target) = 0;
 		virtual void copyImpl(TexturePtr& target) = 0;
-
 		/// @copydoc Resource::calculateSize
 		/// @copydoc Resource::calculateSize
 		UINT32 calculateSize(void) const;
 		UINT32 calculateSize(void) const;
 
 

+ 16 - 3
CamelotCore/Include/CmTextureRTTI.h

@@ -5,6 +5,8 @@
 #include "CmTexture.h"
 #include "CmTexture.h"
 #include "CmManagedDataBlock.h"
 #include "CmManagedDataBlock.h"
 #include "CmMath.h"
 #include "CmMath.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 
 // DEBUG ONLY
 // DEBUG ONLY
 #include "CmTextureManager.h"
 #include "CmTextureManager.h"
@@ -32,7 +34,15 @@ namespace CamelotFramework
 			UINT32 face = (size_t)Math::Floor(idx / (float)(obj->getNumMipmaps() + 1));
 			UINT32 face = (size_t)Math::Floor(idx / (float)(obj->getNumMipmaps() + 1));
 			UINT32 mipmap = idx % (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)
 		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 face = (size_t)Math::Floor(i / (float)(texture->getNumMipmaps() + 1));
 				UINT32 mipmap = i % (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);
 			CM_DELETE(pixelData, vector<PixelDataPtr>, PoolAlloc);
 			texture->mRTTIData = nullptr;	
 			texture->mRTTIData = nullptr;	
 		}
 		}

+ 11 - 1
CamelotCore/Source/CmApplication.cpp

@@ -25,7 +25,6 @@
 #include "CmMaterialManager.h"
 #include "CmMaterialManager.h"
 #include "CmFontManager.h"
 #include "CmFontManager.h"
 #include "CmRenderer.h"
 #include "CmRenderer.h"
-#include "CmDeferredRenderContext.h"
 
 
 #include "CmMaterial.h"
 #include "CmMaterial.h"
 #include "CmShader.h"
 #include "CmShader.h"
@@ -60,6 +59,7 @@ namespace CamelotFramework
 		RenderSystem* renderSystem = RenderSystem::instancePtr();
 		RenderSystem* renderSystem = RenderSystem::instancePtr();
 
 
 		mPrimaryRenderContext = renderSystem->createDeferredContext();
 		mPrimaryRenderContext = renderSystem->createDeferredContext();
+		mPrimarySyncedRenderContext = &renderSystem->getSyncedDeferredContext();
 
 
 		SceneManager::startUp((SceneManager*)loadPlugin(desc.sceneManager));
 		SceneManager::startUp((SceneManager*)loadPlugin(desc.sceneManager));
 
 
@@ -204,4 +204,14 @@ namespace CamelotFramework
 		static Application application;
 		static Application application;
 		return 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
 namespace CamelotFramework
 {
 {
 #if CM_DEBUG_MODE
 #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)
 		: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);
 			CM_LOCK_MUTEX(CommandQueueBreakpointMutex);
@@ -19,14 +19,14 @@ namespace CamelotFramework
 		}
 		}
 	}
 	}
 #else
 #else
-	CommandQueue::CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
+	CommandQueueBase::CommandQueueBase(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
 		:mMyThreadId(threadId), mAllowAllThreads(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
 #endif
 
 
-	CommandQueue::~CommandQueue()
+	CommandQueueBase::~CommandQueueBase()
 	{
 	{
 #if CM_DEBUG_MODE
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
 #if CM_THREAD_SUPPORT != 0
@@ -38,79 +38,74 @@ namespace CamelotFramework
 #endif
 #endif
 
 
 		if(mCommands != nullptr)
 		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
 #if CM_DEBUG_MODE
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 
 
-		Command newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
 #else
 #else
-		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 #endif
 #endif
 
 
 		mCommands->push(newCommand);
 		mCommands->push(newCommand);
 
 
 #if CM_FORCE_SINGLETHREADED_RENDERING
 #if CM_FORCE_SINGLETHREADED_RENDERING
-		std::queue<CommandQueue::Command>* commands = flush();
+		std::queue<QueuedCommand>* commands = flush();
 		playback(commands);
 		playback(commands);
 #endif
 #endif
 
 
 		return newCommand.asyncOp;
 		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
 #if CM_DEBUG_MODE
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 		breakIfNeeded(mCommandQueueIdx, mMaxDebugIdx);
 
 
-		Command newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, mMaxDebugIdx++, _notifyWhenComplete, _callbackId);
 #else
 #else
-		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
+		QueuedCommand newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 #endif
 #endif
 
 
 		mCommands->push(newCommand);
 		mCommands->push(newCommand);
 
 
 #if CM_FORCE_SINGLETHREADED_RENDERING
 #if CM_FORCE_SINGLETHREADED_RENDERING
-		std::queue<CommandQueue::Command>* commands = flush();
+		std::queue<QueuedCommand>* commands = flush();
 		playback(commands);
 		playback(commands);
 #endif
 #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;
 		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
 #if CM_DEBUG_MODE
 		RenderSystem* rs = RenderSystem::instancePtr();
 		RenderSystem* rs = RenderSystem::instancePtr();
@@ -124,7 +119,7 @@ namespace CamelotFramework
 
 
 		while(!commands->empty())
 		while(!commands->empty())
 		{
 		{
-			Command& command = commands->front();
+			QueuedCommand& command = commands->front();
 
 
 			if(command.returnsValue)
 			if(command.returnsValue)
 			{
 			{
@@ -150,24 +145,22 @@ namespace CamelotFramework
 			commands->pop();
 			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)>());
 		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)
 		if(mCommands != nullptr && mCommands->size() > 0)
 			return false;
 			return false;
 
 
@@ -175,12 +168,14 @@ namespace CamelotFramework
 	}
 	}
 
 
 #if CM_DEBUG_MODE
 #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;
 		size_t seed = 0;
 		hash_combine(seed, v.queueIdx);
 		hash_combine(seed, v.queueIdx);
@@ -188,19 +183,19 @@ namespace CamelotFramework
 		return seed;
 		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;
 		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);
 		CM_LOCK_MUTEX(CommandQueueBreakpointMutex);
 
 
 		SetBreakpoints.insert(QueueBreakpoint(queueIdx, commandIdx));
 		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
 		// 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.
 		// will only be added at the start of the application, so race conditions should not occur.
@@ -212,7 +207,7 @@ namespace CamelotFramework
 		}
 		}
 	}
 	}
 #else
 #else
-	void CommandQueue::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
+	void CommandQueueBase::addBreakpoint(UINT32 queueIdx, UINT32 commandIdx)
 	{
 	{
 		// Do nothing, no breakpoints in release
 		// Do nothing, no breakpoints in release
 	}
 	}

+ 0 - 172
CamelotCore/Source/CmDeferredRenderContext.cpp

@@ -9,177 +9,5 @@
 
 
 namespace CamelotFramework
 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 "CmBlendState.h"
 #include "CmDepthStencilState.h"
 #include "CmDepthStencilState.h"
 #include "CmPassRTTI.h"
 #include "CmPassRTTI.h"
-#include "CmDeferredRenderContext.h"
 #include "CmMaterial.h"
 #include "CmMaterial.h"
 #include "CmGpuParams.h"
 #include "CmGpuParams.h"
 #include "CmException.h"
 #include "CmException.h"
@@ -106,37 +105,37 @@ namespace CamelotFramework
 		return mStencilRefValue;
 		return mStencilRefValue;
 	}
 	}
 	//----------------------------------------------------------------------
 	//----------------------------------------------------------------------
-	void Pass::activate(DeferredRenderContextPtr& renderContext) const
+	void Pass::activate(RenderContext& renderContext) const
 	{
 	{
 		HGpuProgram vertProgram = getVertexProgram();
 		HGpuProgram vertProgram = getVertexProgram();
 		if(vertProgram)
 		if(vertProgram)
-			renderContext->bindGpuProgram(vertProgram);
+			renderContext.bindGpuProgram(vertProgram);
 		else
 		else
-			renderContext->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_VERTEX_PROGRAM);
 
 
 		HGpuProgram fragProgram = getFragmentProgram();
 		HGpuProgram fragProgram = getFragmentProgram();
 		if(fragProgram)
 		if(fragProgram)
-			renderContext->bindGpuProgram(fragProgram);
+			renderContext.bindGpuProgram(fragProgram);
 		else
 		else
-			renderContext->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 
 
 		HGpuProgram geomProgram = getGeometryProgram();
 		HGpuProgram geomProgram = getGeometryProgram();
 		if(geomProgram)
 		if(geomProgram)
-			renderContext->bindGpuProgram(geomProgram);
+			renderContext.bindGpuProgram(geomProgram);
 		else
 		else
-			renderContext->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 
 
 		HGpuProgram hullProgram = getHullProgram();
 		HGpuProgram hullProgram = getHullProgram();
 		if(hullProgram)
 		if(hullProgram)
-			renderContext->bindGpuProgram(hullProgram);
+			renderContext.bindGpuProgram(hullProgram);
 		else
 		else
-			renderContext->unbindGpuProgram(GPT_HULL_PROGRAM);
+			renderContext.unbindGpuProgram(GPT_HULL_PROGRAM);
 
 
 		HGpuProgram domainProgram = getDomainProgram();
 		HGpuProgram domainProgram = getDomainProgram();
 		if(domainProgram)
 		if(domainProgram)
-			renderContext->bindGpuProgram(domainProgram);
+			renderContext.bindGpuProgram(domainProgram);
 		else
 		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)
 		// 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
 		// Set up non-texture related pass settings
 		HBlendState blendState = getBlendState();
 		HBlendState blendState = getBlendState();
 		if(blendState != nullptr)
 		if(blendState != nullptr)
-			renderContext->setBlendState(blendState.getInternalPtr());
+			renderContext.setBlendState(blendState.getInternalPtr());
 		else
 		else
-			renderContext->setBlendState(BlendState::getDefault());
+			renderContext.setBlendState(BlendState::getDefault());
 
 
 		HDepthStencilState depthStancilState = getDepthStencilState();
 		HDepthStencilState depthStancilState = getDepthStencilState();
 		if(depthStancilState != nullptr)
 		if(depthStancilState != nullptr)
-			renderContext->setDepthStencilState(depthStancilState.getInternalPtr(), getStencilRefValue());
+			renderContext.setDepthStencilState(depthStancilState.getInternalPtr(), getStencilRefValue());
 		else
 		else
-			renderContext->setDepthStencilState(DepthStencilState::getDefault(), getStencilRefValue());
+			renderContext.setDepthStencilState(DepthStencilState::getDefault(), getStencilRefValue());
 
 
 		HRasterizerState rasterizerState = getRasterizerState();
 		HRasterizerState rasterizerState = getRasterizerState();
 		if(rasterizerState != nullptr)
 		if(rasterizerState != nullptr)
-			renderContext->setRasterizerState(rasterizerState.getInternalPtr());
+			renderContext.setRasterizerState(rasterizerState.getInternalPtr());
 		else
 		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();
 		HGpuProgram vertProgram = getVertexProgram();
 		if(vertProgram)
 		if(vertProgram)
-			renderContext->bindGpuParams(GPT_VERTEX_PROGRAM, GpuParams::createBindableCopy(params->mVertParams));
+			renderContext.bindGpuParams(GPT_VERTEX_PROGRAM, GpuParams::createBindableCopy(params->mVertParams));
 
 
 		HGpuProgram fragProgram = getFragmentProgram();
 		HGpuProgram fragProgram = getFragmentProgram();
 		if(fragProgram)
 		if(fragProgram)
-			renderContext->bindGpuParams(GPT_FRAGMENT_PROGRAM, GpuParams::createBindableCopy(params->mFragParams));
+			renderContext.bindGpuParams(GPT_FRAGMENT_PROGRAM, GpuParams::createBindableCopy(params->mFragParams));
 
 
 		HGpuProgram geomProgram = getGeometryProgram();
 		HGpuProgram geomProgram = getGeometryProgram();
 		if(geomProgram)
 		if(geomProgram)
-			renderContext->bindGpuParams(GPT_GEOMETRY_PROGRAM, GpuParams::createBindableCopy(params->mGeomParams));
+			renderContext.bindGpuParams(GPT_GEOMETRY_PROGRAM, GpuParams::createBindableCopy(params->mGeomParams));
 
 
 		HGpuProgram hullProgram = getHullProgram();
 		HGpuProgram hullProgram = getHullProgram();
 		if(hullProgram)
 		if(hullProgram)
-			renderContext->bindGpuParams(GPT_HULL_PROGRAM, GpuParams::createBindableCopy(params->mHullParams));
+			renderContext.bindGpuParams(GPT_HULL_PROGRAM, GpuParams::createBindableCopy(params->mHullParams));
 
 
 		HGpuProgram domainProgram = getDomainProgram();
 		HGpuProgram domainProgram = getDomainProgram();
 		if(domainProgram)
 		if(domainProgram)
-			renderContext->bindGpuParams(GPT_DOMAIN_PROGRAM, GpuParams::createBindableCopy(params->mDomainParams));
+			renderContext.bindGpuParams(GPT_DOMAIN_PROGRAM, GpuParams::createBindableCopy(params->mDomainParams));
 
 
 		HGpuProgram computeProgram = getComputeProgram();
 		HGpuProgram computeProgram = getComputeProgram();
 		if(computeProgram)
 		if(computeProgram)
-			renderContext->bindGpuParams(GPT_COMPUTE_PROGRAM, GpuParams::createBindableCopy(params->mComputeParams));
+			renderContext.bindGpuParams(GPT_COMPUTE_PROGRAM, GpuParams::createBindableCopy(params->mComputeParams));
 	}
 	}
 	//----------------------------------------------------------------------
 	//----------------------------------------------------------------------
 	RTTITypeBase* Pass::getRTTIStatic()
 	RTTITypeBase* Pass::getRTTIStatic()

+ 22 - 8
CamelotCore/Source/CmRenderSystem.cpp

@@ -33,14 +33,13 @@ THE SOFTWARE.
 
 
 #include "CmRenderSystem.h"
 #include "CmRenderSystem.h"
 
 
+#include "CmDeferredRenderContext.h"
 #include "CmViewport.h"
 #include "CmViewport.h"
 #include "CmException.h"
 #include "CmException.h"
 #include "CmRenderTarget.h"
 #include "CmRenderTarget.h"
 #include "CmRenderWindow.h"
 #include "CmRenderWindow.h"
 #include "CmPixelBuffer.h"
 #include "CmPixelBuffer.h"
 #include "CmOcclusionQuery.h"
 #include "CmOcclusionQuery.h"
-#include "CmCommandQueue.h"
-#include "CmDeferredRenderContext.h"
 #include "CmGpuResource.h"
 #include "CmGpuResource.h"
 #include "boost/bind.hpp"
 #include "boost/bind.hpp"
 
 
@@ -68,6 +67,7 @@ namespace CamelotFramework {
 		, mRenderThreadShutdown(false)
 		, mRenderThreadShutdown(false)
 		, mCommandQueue(nullptr)
 		, mCommandQueue(nullptr)
 		, mMaxCommandNotifyId(0)
 		, mMaxCommandNotifyId(0)
+		, mSyncedRenderContext(nullptr)
     {
     {
     }
     }
 
 
@@ -80,7 +80,7 @@ namespace CamelotFramework {
 
 
 		if(mCommandQueue != nullptr)
 		if(mCommandQueue != nullptr)
 		{
 		{
-			CM_DELETE(mCommandQueue, CommandQueue, GenAlloc);
+			CM_DELETE(mCommandQueue, CommandQueue<CommandQueueNoSync>, GenAlloc);
 			mCommandQueue = nullptr;
 			mCommandQueue = nullptr;
 		}
 		}
 
 
@@ -91,7 +91,7 @@ namespace CamelotFramework {
 	RenderWindowPtr RenderSystem::initialize(const RENDER_WINDOW_DESC& primaryWindowDesc)
 	RenderWindowPtr RenderSystem::initialize(const RENDER_WINDOW_DESC& primaryWindowDesc)
 	{
 	{
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
 		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;
 		mPrimaryWindowDesc = primaryWindowDesc;
 
 
 		initRenderThread();
 		initRenderThread();
@@ -107,11 +107,18 @@ namespace CamelotFramework {
 		mVertexProgramBound = false;
 		mVertexProgramBound = false;
 		mGeometryProgramBound = false;
 		mGeometryProgramBound = false;
 		mFragmentProgramBound = false;
 		mFragmentProgramBound = false;
+
+		mSyncedRenderContext = CM_NEW(DeferredRenderContext<CommandQueueSync>, GenAlloc) DeferredRenderContext<CommandQueueSync>(this, CM_THREAD_CURRENT_ID);
 	}
 	}
 
 
 	void RenderSystem::destroy_internal()
 	void RenderSystem::destroy_internal()
 	{
 	{
 		mActiveRenderTarget = nullptr;
 		mActiveRenderTarget = nullptr;
+
+		if(mSyncedRenderContext != nullptr)
+		{
+			CM_DELETE(mSyncedRenderContext, DeferredRenderContext<CommandQueueSync>, GenAlloc);
+		}
 	}
 	}
 
 
 	const RenderSystemCapabilities* RenderSystem::getCapabilities(void) const 
 	const RenderSystemCapabilities* RenderSystem::getCapabilities(void) const 
@@ -273,6 +280,7 @@ namespace CamelotFramework {
 		THROW_IF_NOT_RENDER_THREAD;
 		THROW_IF_NOT_RENDER_THREAD;
 
 
 		resource->writeSubresource(subresourceIdx, data);
 		resource->writeSubresource(subresourceIdx, data);
+		data.unlock();
 		asyncOp.completeOperation();
 		asyncOp.completeOperation();
 	}
 	}
 
 
@@ -281,6 +289,7 @@ namespace CamelotFramework {
 		THROW_IF_NOT_RENDER_THREAD;
 		THROW_IF_NOT_RENDER_THREAD;
 
 
 		resource->readSubresource(subresourceIdx, data);
 		resource->readSubresource(subresourceIdx, data);
+		data.unlock();
 		asyncOp.completeOperation();
 		asyncOp.completeOperation();
 	}
 	}
 
 
@@ -324,7 +333,7 @@ namespace CamelotFramework {
 		while(true)
 		while(true)
 		{
 		{
 			// Wait until we get some ready commands
 			// Wait until we get some ready commands
-			std::queue<CommandQueue::Command>* commands = nullptr;
+			std::queue<QueuedCommand>* commands = nullptr;
 			{
 			{
 				CM_LOCK_MUTEX_NAMED(mCommandQueueMutex, lock)
 				CM_LOCK_MUTEX_NAMED(mCommandQueueMutex, lock)
 
 
@@ -373,10 +382,15 @@ namespace CamelotFramework {
 		mRenderThreadStarted = false;
 		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)
 	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;
 		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);
 		PixelData myData = lock(GBL_WRITE_ONLY_DISCARD, mip, face);
-		PixelUtil::bulkPixelConversion(data, myData);
+		PixelUtil::bulkPixelConversion(pixelData, myData);
 		unlock();
 		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 numMips = getNumMipmaps();
 		UINT32 width = getWidth();
 		UINT32 width = getWidth();
 		UINT32 height = getHeight();
 		UINT32 height = getHeight();
@@ -142,24 +159,23 @@ namespace CamelotFramework {
 			&MemAllocDeleter<PixelData, PoolAlloc>::deleter);
 			&MemAllocDeleter<PixelData, PoolAlloc>::deleter);
 
 
 		dst->allocateInternalBuffer(totalSize);
 		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)
 	PixelData Texture::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
 	{

+ 6 - 1
CamelotFontImporter/Source/CmFontImporter.cpp

@@ -5,6 +5,8 @@
 #include "CmResources.h"
 #include "CmResources.h"
 #include "CmDebug.h"
 #include "CmDebug.h"
 #include "CmTexAtlasGenerator.h"
 #include "CmTexAtlasGenerator.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 
 #include <ft2build.h>
 #include <ft2build.h>
 #include <freetype/freetype.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);
 				HTexture newTex = Texture::create(TEX_TYPE_2D, pageIter->width, pageIter->height, 0, PF_R8G8);
 				newTex.waitUntilLoaded();
 				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);
 				fontData.texturePages.push_back(newTex);
 
 

+ 5 - 1
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -7,6 +7,8 @@
 #include "CmTextureManager.h"
 #include "CmTextureManager.h"
 #include "CmTexture.h"
 #include "CmTexture.h"
 #include "CmFileSystem.h"
 #include "CmFileSystem.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderContext.h"
 
 
 #include "FreeImage.h"
 #include "FreeImage.h"
 
 
@@ -132,7 +134,9 @@ namespace CamelotFramework
 		{
 		{
 			PixelData src = imgData->getPixels(mip);
 			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();
 		fileData->close();

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

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

+ 6 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

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

+ 5 - 5
CamelotUtility/Include/CmAsyncOp.h

@@ -8,11 +8,11 @@ namespace CamelotFramework
 {
 {
 	/**
 	/**
 	 * @brief	Asynchronous operation. Contains uninitialized data until
 	 * @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.
 	 * @note	You are allowed (and meant to) to copy this by value.
 	 */
 	 */
-	class AsyncOp
+	class CM_UTILITY_EXPORT AsyncOp
 	{
 	{
 	private:
 	private:
 		struct AsyncOpData
 		struct AsyncOpData
@@ -22,7 +22,7 @@ namespace CamelotFramework
 			{ }
 			{ }
 
 
 			boost::any mReturnValue;
 			boost::any mReturnValue;
-			bool mIsCompleted;
+			volatile bool mIsCompleted;
 		};
 		};
 
 
 	public:
 	public:
@@ -38,12 +38,12 @@ namespace CamelotFramework
 		/**
 		/**
 		 * @brief	Mark the async operation as completed.
 		 * @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;
 		 * @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.
 		 * @brief	Retrieves the value returned by the async operation.

+ 3 - 5
CamelotUtility/Include/CmMath.h

@@ -231,11 +231,6 @@ namespace CamelotFramework
         */
         */
         ~Math();
         ~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 float Abs (float fValue) { return float(fabs(fValue)); }
 		static inline Degree Abs (const Degree& dValue) { return Degree(fabs(dValue.valueDegrees())); }
 		static inline Degree Abs (const Degree& dValue) { return Degree(fabs(dValue.valueDegrees())); }
 		static inline Radian Abs (const Radian& rValue) { return Radian(fabs(rValue.valueRadians())); }
 		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 ATan (float fValue) { return Radian(atan(fValue)); }
 		static inline Radian ATan2 (float fY, float fX) { return Radian(atan2(fY,fX)); }
 		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 float Ceil (float fValue) { return float(ceil(fValue)); }
+		static inline int CeilToInt (float fValue) { return int(ceil(fValue)); }
 		static inline bool isNaN(float f)
 		static inline bool isNaN(float f)
 		{
 		{
 			// std::isnan() is C99, not supported by all compilers
 			// 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 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)); }
 		static inline float Log (float fValue) { return float(log(fValue)); }
 
 
 		/// Stored value of log(2) for frequent use
 		/// 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_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(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_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
 // like CM_AUTO_MUTEX but mutex held by pointer
 #define CM_AUTO_SHARED_MUTEX mutable boost::recursive_mutex *CM_AUTO_MUTEX_NAME;
 #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);
 #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_STATIC_MUTEX_CLASS_INSTANCE(name, classTypeName)
 #define CM_LOCK_MUTEX(name)
 #define CM_LOCK_MUTEX(name)
 #define CM_LOCK_MUTEX_NAMED(mutexName, lockName)
 #define CM_LOCK_MUTEX_NAMED(mutexName, lockName)
+#define CM_LOCK_TYPE UINT32
 #define CM_AUTO_SHARED_MUTEX
 #define CM_AUTO_SHARED_MUTEX
 #define CM_LOCK_AUTO_SHARED_MUTEX
 #define CM_LOCK_AUTO_SHARED_MUTEX
 #define CM_COPY_AUTO_SHARED_MUTEX(from)
 #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];
 		return mTanTable[idx];
     }
     }
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
-    int Math::ISign (int iValue)
-    {
-        return ( iValue > 0 ? +1 : ( iValue < 0 ? -1 : 0 ) );
-    }
-    //-----------------------------------------------------------------------
     Radian Math::ACos (float fValue)
     Radian Math::ACos (float fValue)
     {
     {
         if ( -1.0 < 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?
    - input lag?
 
 
 <<<<<<<Resource update/read>>>>>>>>
 <<<<<<<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.
  - 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?
   - 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
   - I probably want to determine front faces based on normals