Browse Source

New deferred context works!

Marko Pintera 13 năm trước cách đây
mục cha
commit
6166de8dc2

+ 1 - 1
CamelotD3D9Renderer/Include/CmD3D9RenderSystem.h

@@ -177,6 +177,7 @@ namespace CamelotEngine
 		friend class D3D9TextureManager;
 
 		void startUp_internal();
+		void shutdown_internal();
 
 		void setClipPlanesImpl(const PlaneList& clipPlanes);	
 
@@ -224,7 +225,6 @@ namespace CamelotEngine
 		~D3D9RenderSystem();
 
 		const String& getName() const;
-		void shutdown_internal();
 
 		void setStencilCheckEnabled_internal(bool enabled);
         void setStencilBufferParams_internal(CompareFunction func = CMPF_ALWAYS_PASS, 

+ 34 - 35
CamelotForwardRenderer/Source/CmForwardRenderer.cpp

@@ -1,8 +1,7 @@
 #include "CmForwardRenderer.h"
 #include "CmCamera.h"
 #include "CmSceneManager.h"
-#include "CmRenderSystemManager.h"
-#include "CmRenderSystem.h"
+#include "CmDeferredRenderContext.h"
 #include "CmRenderable.h"
 #include "CmMaterial.h"
 #include "CmMesh.h"
@@ -26,11 +25,11 @@ namespace CamelotEngine
 
 	void ForwardRenderer::renderAll() 
 	{
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
 
 		// TODO - No point in setting these each frame?
-		renderSystem->setInvertVertexWinding(false);
-		renderSystem->setDepthBufferParams();
+		renderContext->setInvertVertexWinding(false);
+		renderContext->setDepthBufferParams();
 
 		const vector<CameraPtr>::type& allCameras = gSceneManager().getAllCameras();
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
@@ -38,23 +37,23 @@ namespace CamelotEngine
 			render(*iter);
 		}
 
-		renderSystem->swapAllRenderTargetBuffers(false);
+		renderContext->swapAllRenderTargetBuffers(false);
 	}
 
 	void ForwardRenderer::render(const CameraPtr camera) 
 	{
 		vector<RenderablePtr>::type allRenderables = gSceneManager().getVisibleRenderables(camera);
 
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
-		renderSystem->setViewport(*camera->getViewport());
+		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
+		renderContext->setViewport(*camera->getViewport());
 
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
-		renderSystem->clearFrameBuffer(FBT_COLOUR | FBT_DEPTH, Color::Blue);
-		renderSystem->beginFrame();
+		renderContext->clearFrameBuffer(FBT_COLOUR | FBT_DEPTH, Color::Blue);
+		renderContext->beginFrame();
 
 		// TODO - sort renderables by material/pass/parameters to minimize state changes
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
@@ -79,11 +78,11 @@ namespace CamelotEngine
 				setPass(material->getPass(i));
 				setPassParameters(material->getPassParameters(i));
 
-				renderSystem->render(mesh->getRenderOperation());
+				renderContext->render(mesh->getRenderOperation());
 			}
 		}
 
-		renderSystem->endFrame();
+		renderContext->endFrame();
 
 		// TODO - Sort renderables
 		// Render them
@@ -96,39 +95,39 @@ namespace CamelotEngine
 
 		mActivePass = pass;
 
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
 
 		GpuProgramHandle vertProgram = pass->getVertexProgram();
 		if(vertProgram)
 		{
-			renderSystem->bindGpuProgram(vertProgram);
+			renderContext->bindGpuProgram(vertProgram);
 		}
 		else
 		{
 			//if(renderSystem->isGpuProgramBound(GPT_VERTEX_PROGRAM))
-				renderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+				renderContext->unbindGpuProgram(GPT_VERTEX_PROGRAM);
 		}
 
 		GpuProgramHandle fragProgram = pass->getFragmentProgram();
 		if(fragProgram)
 		{
-			renderSystem->bindGpuProgram(fragProgram);
+			renderContext->bindGpuProgram(fragProgram);
 		}
 		else
 		{
 			//if(renderSystem->isGpuProgramBound(GPT_FRAGMENT_PROGRAM))
-				renderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
+				renderContext->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 		}
 
 		GpuProgramHandle geomProgram = pass->getGeometryProgram();
 		if(geomProgram)
 		{
-			renderSystem->bindGpuProgram(geomProgram);
+			renderContext->bindGpuProgram(geomProgram);
 		}	
 		else
 		{
 			//if(renderSystem->isGpuProgramBound(GPT_GEOMETRY_PROGRAM))
-				renderSystem->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
+				renderContext->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 		}
 
 		// The rest of the settings are the same no matter whether we use programs or not
@@ -136,7 +135,7 @@ namespace CamelotEngine
 		// Set scene blending
 		if ( pass->hasSeparateSceneBlending( ) )
 		{
-			renderSystem->setSeparateSceneBlending(
+			renderContext->setSeparateSceneBlending(
 				pass->getSourceBlendFactor(), pass->getDestBlendFactor(),
 				pass->getSourceBlendFactorAlpha(), pass->getDestBlendFactorAlpha(),
 				pass->getSceneBlendingOperation(), 
@@ -146,20 +145,20 @@ namespace CamelotEngine
 		{
 			if(pass->hasSeparateSceneBlendingOperations( ) )
 			{
-				renderSystem->setSeparateSceneBlending(
+				renderContext->setSeparateSceneBlending(
 					pass->getSourceBlendFactor(), pass->getDestBlendFactor(),
 					pass->getSourceBlendFactor(), pass->getDestBlendFactor(),
 					pass->getSceneBlendingOperation(), pass->getSceneBlendingOperationAlpha() );
 			}
 			else
 			{
-				renderSystem->setSceneBlending(
+				renderContext->setSceneBlending(
 					pass->getSourceBlendFactor(), pass->getDestBlendFactor(), pass->getSceneBlendingOperation() );
 			}
 		}
 
 		// Set point parameters
-		renderSystem->setPointParameters(
+		renderContext->setPointParameters(
 			pass->getPointSize(),
 			false, 
 			false, 
@@ -176,45 +175,45 @@ namespace CamelotEngine
 
 		// Set up non-texture related material settings
 		// Depth buffer settings
-		renderSystem->setDepthBufferFunction(pass->getDepthFunction());
-		renderSystem->setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
-		renderSystem->setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
-		renderSystem->setDepthBias(pass->getDepthBiasConstant(), pass->getDepthBiasSlopeScale());
+		renderContext->setDepthBufferFunction(pass->getDepthFunction());
+		renderContext->setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
+		renderContext->setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
+		renderContext->setDepthBias(pass->getDepthBiasConstant(), pass->getDepthBiasSlopeScale());
 
 		// Alpha-reject settings
-		renderSystem->setAlphaRejectSettings(
+		renderContext->setAlphaRejectSettings(
 			pass->getAlphaRejectFunction(), pass->getAlphaRejectValue(), pass->isAlphaToCoverageEnabled());
 
 		// Set colour write mode
 		// Right now we only use on/off, not per-channel
 		bool colWrite = pass->getColourWriteEnabled();
-		renderSystem->setColorBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
+		renderContext->setColorBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
 
 		// Culling mode
-		renderSystem->setCullingMode(pass->getCullingMode());
+		renderContext->setCullingMode(pass->getCullingMode());
 
 		// Polygon mode
-		renderSystem->setPolygonMode(pass->getPolygonMode());
+		renderContext->setPolygonMode(pass->getPolygonMode());
 	}
 
 	void ForwardRenderer::setPassParameters(PassParametersPtr params)
 	{
 		// TODO - When applying passes, don't re-apply states that are already the same as from previous pass.
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderContextPtr renderContext = gApplication().getPrimaryRenderContext();
 
 		if(mActivePass == nullptr)
 			CM_EXCEPT(InternalErrorException, "Trying to set pass parameters, but no pass is set.");
 
 		GpuProgramHandle vertProgram = mActivePass->getVertexProgram();
 		if(vertProgram)
-			renderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, params->mVertParams, GPV_ALL);
+			renderContext->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, params->mVertParams, GPV_ALL);
 
 		GpuProgramHandle fragProgram = mActivePass->getFragmentProgram();
 		if(fragProgram)
-			renderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, params->mFragParams, GPV_ALL);
+			renderContext->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, params->mFragParams, GPV_ALL);
 
 		GpuProgramHandle geomProgram = mActivePass->getGeometryProgram();
 		if(geomProgram)
-			renderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, params->mGeomParams, GPV_ALL);
+			renderContext->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, params->mGeomParams, GPV_ALL);
 	}
 }

+ 4 - 4
CamelotGLRenderer/Include/CmGLRenderSystem.h

@@ -132,6 +132,10 @@ namespace CamelotEngine {
           RenderSystem
          */
 		void startUp_internal();
+		/** See
+          RenderSystem
+         */
+        void shutdown_internal(void);
 
 		void setClipPlanesImpl(const PlaneList& clipPlanes);
 		bool activateGLTextureUnit(UINT16 unit);
@@ -190,10 +194,6 @@ namespace CamelotEngine {
         // -----------------------------
         // Low-level overridden members
         // -----------------------------
-        /** See
-          RenderSystem
-         */
-        void shutdown_internal(void);
 		/** See
           RenderSystem
          */

+ 4 - 0
CamelotRenderer/Include/CmApplication.h

@@ -26,6 +26,9 @@ namespace CamelotEngine
 
 			RenderWindow* 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.
 			 *
@@ -35,6 +38,7 @@ namespace CamelotEngine
 
 	private:
 		RenderWindow* mPrimaryRenderWindow;
+		DeferredRenderContextPtr mPrimaryRenderContext;
 
 		/**
 		 * @brief	Callback called from the render thread in order to initialize resources.

+ 40 - 19
CamelotRenderer/Include/CmCommandQueue.h

@@ -16,12 +16,12 @@ namespace CamelotEngine
 	public:
 		struct Command
 		{
-			Command(boost::function<void(AsyncOp&)> _callback, UINT32 _callbackId = 0)
-				:callbackWithReturnValue(_callback), returnsValue(true), callbackId(_callbackId)
+			Command(boost::function<void(AsyncOp&)> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+				:callbackWithReturnValue(_callback), returnsValue(true), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
 			{ }
 
-			Command(boost::function<void()> _callback, UINT32 _callbackId = 0)
-				:callback(_callback), returnsValue(false), callbackId(_callbackId)
+			Command(boost::function<void()> _callback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0)
+				:callback(_callback), returnsValue(false), notifyWhenComplete(_notifyWhenComplete), callbackId(_callbackId)
 			{ }
 
 			boost::function<void()> callback;
@@ -29,9 +29,21 @@ namespace CamelotEngine
 			AsyncOp asyncOp;
 			bool returnsValue;
 			UINT32 callbackId;
+			bool notifyWhenComplete;
 		};
 
-		CommandQueue(CM_THREAD_ID_TYPE threadId);
+		/**
+		 * @brief	Constructor.
+		 *
+		 * @param	threadId	   	Identifier for the thread the command queue will be used on.
+		 * @param	allowAllThreads	Only matters for debug purposes. If false, then the queue
+		 * 							will throw an exception if accessed outside of the creation thread
+		 * 							(If in debug mode).
+		 * 							
+		 *							When you want to allow multiple threads to access it, set this to true,
+		 *							and also make sure you sync access to the queue properly.
+		 */
+		CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads = false);
 		~CommandQueue();
 
 		CM_THREAD_ID_TYPE getThreadId() const { return mMyThreadId; }
@@ -46,6 +58,8 @@ namespace CamelotEngine
 		 * 			processing. (If it doesn't it will still be called automatically, but the return
 		 * 			value will default to nullptr)
 		 *
+		 * @param	_notifyWhenComplete	(optional) Call the notify method (provided in the call to CommandQueue::playback)
+		 * 								when the command is complete.
 		 * @param	_callbackId			   	(optional) Identifier for the callback so you can then later find it
 		 * 									if needed.
 		 *
@@ -53,18 +67,20 @@ namespace CamelotEngine
 		 * 			it completes AsyncOp::isResolved will return true and return data will be valid (if
 		 * 			the callback provided any).
 		 */
-		AsyncOp queueReturn(boost::function<void(AsyncOp&)> commandCallback, UINT32 _callbackId = 0);
+		AsyncOp queueReturn(boost::function<void(AsyncOp&)> commandCallback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0);
 
 		/**
 		 * @brief	Queue up a new command to execute. Make sure the provided function has all of its
-		 * 			parameters properly bound. Provided command is not expected to return a value.
-		 * 			If you wish to return a value from the callback use the other overload of queueCommand 
-		 * 			which accepts AsyncOp parameter.
+		 * 			parameters properly bound. Provided command is not expected to return a value. If you
+		 * 			wish to return a value from the callback use the other overload of queueCommand which
+		 * 			accepts AsyncOp parameter.
 		 *
-		 * @param	_callbackId			   	(optional) Identifier for the callback so you can then later find it
-		 * 									if needed.
+		 * @param	_notifyWhenComplete	(optional) Call the notify method (provided in the call to CommandQueue::playback)
+		 * 								when the command is complete.
+		 * @param	_callbackId		   	(optional) Identifier for the callback so you can then later find
+		 * 								it if needed.
 		 */
-		void queue(boost::function<void()> commandCallback, UINT32 _callbackId = 0);
+		void queue(boost::function<void()> commandCallback, bool _notifyWhenComplete = false, UINT32 _callbackId = 0);
 
 		/**
 		 * @brief	Returns a copy of all queued commands and makes room for new ones. Must be called from the thread
@@ -72,6 +88,15 @@ namespace CamelotEngine
 		 */
 		vector<Command>::type* flush();
 
+		/**
+		 * @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(vector<Command>::type* 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().
@@ -79,21 +104,17 @@ namespace CamelotEngine
 		void playback(vector<Command>::type* commands);
 
 		/**
-		 * @brief	Blocks the current thread until all commands in the context are processed.
-		 * 			
-		 * @note	Do not call from render thread. Render thread is the thread doing the processing and blocking
-		 * 			it will cause a deadlock since processing will never be completed. 
+		 * @brief	Returns true if no commands are queued.
 		 */
-		void blockUntilExecuted();
+		bool isEmpty();
 
 	private:
 		vector<Command>::type* mCommands;
 
 		bool mIsShutdown;
-		bool mIsExecuting;
+		bool mAllowAllThreads;
 
 		CM_THREAD_ID_TYPE mMyThreadId;
 		CM_MUTEX(mCommandBufferMutex);
-		CM_THREAD_SYNCHRONISER(mContextPlaybackDoneCondition);
 	};
 }

+ 2 - 0
CamelotRenderer/Include/CmPrerequisites.h

@@ -110,6 +110,7 @@ namespace CamelotEngine {
 	class HardwareBufferManagerBase;
 	class HardwareConstantBuffer;
 	class CommandQueue;
+	class DeferredRenderContext;
 	// Asset import
 	class SpecificImporter;
 	class Importer;
@@ -151,6 +152,7 @@ namespace CamelotEngine
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<GameObject> GameObjectPtr;
 	typedef std::shared_ptr<HardwareConstantBuffer> HardwareConstantBufferPtr;
+	typedef std::shared_ptr<DeferredRenderContext> DeferredRenderContextPtr;
 }
 
 // All type IDs

+ 35 - 33
CamelotRenderer/Include/CmRenderSystem.h

@@ -114,7 +114,6 @@ namespace CamelotEngine
 		/** Shutdown the renderer and cleanup resources.
 		*/
 		void shutdown(void);
-		virtual void shutdown_internal(void);
 
 		/** Creates a new rendering window.
 		@remarks
@@ -901,6 +900,7 @@ namespace CamelotEngine
 		RenderSystemCapabilities* mCurrentCapabilities;
 
 		virtual void startUp_internal();
+		virtual void shutdown_internal();
 
 		/// Internal method used to set the underlying clip planes when needed
 		virtual void setClipPlanesImpl(const PlaneList& clipPlanes) = 0;
@@ -942,22 +942,27 @@ namespace CamelotEngine
 		bool mRenderThreadShutdown;
 
 		CM_THREAD_ID_TYPE mRenderThreadId;
-		CM_THREAD_SYNCHRONISER(mRSContextInitCondition)
+		CM_THREAD_SYNCHRONISER(mRenderThreadStartCondition)
 		CM_MUTEX(mRSContextInitMutex)
 		CM_THREAD_SYNCHRONISER(mCommandReadyCondition)
-		CM_MUTEX(mRSContextMutex)
+		CM_MUTEX(mCommandQueueMutex)
+		CM_THREAD_SYNCHRONISER(mCommandQueueCompleteCondition)
+		CM_MUTEX(mCommandCompleteMutex)
 		CM_MUTEX(mRSRenderCallbackMutex)
-		CM_MUTEX(mResourceContextMutex)
 		CM_MUTEX(mActiveContextMutex)
 
+		CM_MUTEX(mCommandNotifyMutex)
+		CM_THREAD_SYNCHRONISER(mCommandCompleteCondition)
+
 #if CM_THREAD_SUPPORT
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 
 		CommandQueue* mCommandQueue;
 
-		// Context on which all resource commands are queued
-		mutable RenderSystemContextPtr mResourceContext;
+		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
+
 		// Primary context created when the render system is first started up
 		RenderSystemContextPtr mPrimaryContext;
 		// Currently active context. All new commands will be executed on this context.
@@ -1006,17 +1011,6 @@ namespace CamelotEngine
 		 */
 		void submitToGpu(RenderSystemContextPtr context, bool blockUntilComplete);
 
-		/**
-		 * @brief	Creates a new render system context that you can use for rendering on 
-		 * 			a non-render thread. You can have as many of these as you wish, the only limitation
-		 * 			is that you do not use a single instance on more than one thread. Each thread
-		 * 			requires its own context.
-		 * 			
-		 *			Resource context is different from normal rendering context, as it will continously queue commands,
-		 *			while normal "frame" context will discard older batches of commands (i.e. older frames).
-		 */
-		RenderSystemContextPtr createResourceRenderSystemContext();
-
 		/**
 		 * @brief	Gets the currently active render system object.
 		 *
@@ -1024,6 +1018,20 @@ namespace CamelotEngine
 		 */
 		RenderSystemContextPtr getActiveContext() const;
 
+		/**
+		 * @brief	Blocks the calling thread until the command with the specified ID completes.
+		 * 			Make sure that the specified ID actually exists, otherwise this will block forever.
+		 */
+		void blockUntilCommandCompleted(UINT32 commandId);
+
+		/**
+		 * @brief	Callback called by the command list when a specific command finishes executing.
+		 * 			This is only called on commands that have a special notify on complete flag set.
+		 *
+		 * @param	commandId	Identifier for the command.
+		 */
+		void commandCompletedNotify(UINT32 commandId);
+
 	public:
 		/**
 		 * @brief	Returns the id of the render thread. If a separate render thread
@@ -1040,6 +1048,14 @@ namespace CamelotEngine
 		 */
 		RenderSystemContextPtr createRenderSystemContext();
 
+		/**
+		 * @brief	Creates a new render system context that you can use for rendering on 
+		 * 			a non-render thread. You can have as many of these as you wish, the only limitation
+		 * 			is that you do not use a single instance on more than one thread. Each thread
+		 * 			requires its own context. The context will be bound to the thread you call this method on.
+		 */
+		DeferredRenderContextPtr createDeferredContext();
+
 		/**
 		 * @brief	Sets an active context on which all subsequent RenderSystem calls will be executed on.
 		 * 			
@@ -1047,20 +1063,6 @@ namespace CamelotEngine
 		 */
 		void setActiveContext(RenderSystemContextPtr context);
 
-		/**
-		 * @brief	Queues a new command that will be added to the resource context.
-		 * 	
-		 * @see		RenderSystemContext::queueReturnCommand
-		 */
-		AsyncOp queueResourceReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete = false, UINT32 _callbackId = 0);
-
-		/**
-		 * @brief	Queues a new command that will be added to the resource context.
-		 * 	
-		 * @see		RenderSystemContext::queueCommand
-		 */
-		void queueResourceCommand(boost::function<void()> commandCallback, bool blockUntilComplete = false, UINT32 _callbackId = 0);
-
 		/**
 		 * @brief	Queues a new command that will be added to the global command queue. You are allowed to call this from any thread,
 		 * 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
@@ -1070,7 +1072,7 @@ namespace CamelotEngine
 		 * 	
 		 * @see		CommandQueue::queueReturn
 		 */
-		AsyncOp queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete = false, UINT32 _callbackId = 0);
+		AsyncOp queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete = false);
 
 		/**
 		* @brief	Queues a new command that will be added to the global command queue.You are allowed to call this from any thread,
@@ -1080,7 +1082,7 @@ namespace CamelotEngine
 		 * 							   and they all need to be executed in order before the current command is reached, which might take a long time.
 		 * @see		CommandQueue::queue
 		 */
-		void queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete = false, UINT32 _callbackId = 0);
+		void queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete = false);
 
 		/**
 		 * @brief	Callback that is called from the render thread before it starts processing

+ 4 - 1
CamelotRenderer/Source/CmApplication.cpp

@@ -22,6 +22,7 @@
 #include "CmInput.h"
 #include "CmRendererManager.h"
 #include "CmRenderer.h"
+#include "CmDeferredRenderContext.h"
 
 #include "CmMaterial.h"
 #include "CmShader.h"
@@ -52,6 +53,7 @@ namespace CamelotEngine
 		renderSystem->startUp();
 
 		mPrimaryRenderWindow = renderSystem->createRenderWindow("Camelot Renderer", 1280, 720, false);
+		mPrimaryRenderContext = renderSystem->createDeferredContext();
 
 		SceneManager::startUp(new SceneManager());
 		Resources::startUp(new Resources("D:\\CamelotResourceMetas"));
@@ -73,6 +75,7 @@ namespace CamelotEngine
 			gSceneManager().update();
 
 			RendererManager::getActive()->renderAll();
+			mPrimaryRenderContext->submitToGpu();
 
 			RenderSystem* renderSystem = RenderSystemManager::getActive();
 			renderSystem->update();
@@ -97,7 +100,7 @@ namespace CamelotEngine
 		SceneManager::shutDown();
 
 		if(RenderSystemManager::getActive() != nullptr)
-			RenderSystemManager::getActive()->shutdown_internal();
+			RenderSystemManager::getActive()->shutdown();
 
 		HighLevelGpuProgramManager::shutDown();
 		DynLibManager::shutDown();

+ 24 - 43
CamelotRenderer/Source/CmCommandQueue.cpp

@@ -6,8 +6,8 @@
 
 namespace CamelotEngine
 {
-	CommandQueue::CommandQueue(CM_THREAD_ID_TYPE threadId)
-		:mMyThreadId(threadId), mIsExecuting(false)
+	CommandQueue::CommandQueue(CM_THREAD_ID_TYPE threadId, bool allowAllThreads)
+		:mMyThreadId(threadId), mAllowAllThreads(allowAllThreads)
 	{
 		mCommands = new vector<Command>::type();
 	}
@@ -16,7 +16,7 @@ namespace CamelotEngine
 	{
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
-		if(CM_THREAD_CURRENT_ID != mMyThreadId)
+		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
 		{
 			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
 		}
@@ -27,35 +27,35 @@ namespace CamelotEngine
 			delete mCommands;
 	}
 
-	AsyncOp CommandQueue::queueReturn(boost::function<void(AsyncOp&)> commandCallback, UINT32 _callbackId)
+	AsyncOp CommandQueue::queueReturn(boost::function<void(AsyncOp&)> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
 	{
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
-		if(CM_THREAD_CURRENT_ID != mMyThreadId)
+		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
 		{
 			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
 		}
 #endif
 #endif
 
-		Command newCommand(commandCallback, _callbackId);
+		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 		mCommands->push_back(newCommand);
 
 		return newCommand.asyncOp;
 	}
 
-	void CommandQueue::queue(boost::function<void()> commandCallback, UINT32 _callbackId)
+	void CommandQueue::queue(boost::function<void()> commandCallback, bool _notifyWhenComplete, UINT32 _callbackId)
 	{
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
-		if(CM_THREAD_CURRENT_ID != mMyThreadId)
+		if(!mAllowAllThreads && CM_THREAD_CURRENT_ID != mMyThreadId)
 		{
 			CM_EXCEPT(InternalErrorException, "Command queue accessed outside of its creation thread.");
 		}
 #endif
 #endif
 
-		Command newCommand(commandCallback, _callbackId);
+		Command newCommand(commandCallback, _notifyWhenComplete, _callbackId);
 		mCommands->push_back(newCommand);
 	}
 
@@ -72,7 +72,7 @@ namespace CamelotEngine
 		return oldCommands;
 	}
 
-	void CommandQueue::playback(vector<CommandQueue::Command>::type* commands)
+	void CommandQueue::playback(vector<CommandQueue::Command>::type* commands, boost::function<void(UINT32)> notifyCallback)
 	{
 #if CM_DEBUG_MODE
 		RenderSystem* rs = RenderSystemManager::getActive();
@@ -81,22 +81,8 @@ namespace CamelotEngine
 			CM_EXCEPT(InternalErrorException, "This method should only be called from the render thread.");
 #endif
 
-		{
-			CM_LOCK_MUTEX(mCommandBufferMutex)
-
-			mIsExecuting = true;
-		}
-
 		if(commands == nullptr)
-		{
-			{
-				CM_LOCK_MUTEX(mCommandBufferMutex);
-				mIsExecuting = false;
-			}
-
-			CM_THREAD_NOTIFY_ALL(mContextPlaybackDoneCondition);
 			return;
-		}
 
 		for(auto iter = commands->begin(); iter != commands->end(); ++iter)
 		{
@@ -117,33 +103,28 @@ namespace CamelotEngine
 			{
 				command.callback();
 			}
+
+			if(command.notifyWhenComplete && !notifyCallback.empty())
+			{
+				notifyCallback(command.callbackId);
+			}
 		}
 
 		delete commands;
+	}
 
-		{
-			CM_LOCK_MUTEX(mCommandBufferMutex);
-			mIsExecuting = false;
-		}
-
-		CM_THREAD_NOTIFY_ALL(mContextPlaybackDoneCondition)
+	void CommandQueue::playback(vector<Command>::type* commands)
+	{
+		playback(commands, boost::function<void(UINT32)>());
 	}
 
-	void CommandQueue::blockUntilExecuted()
+	bool CommandQueue::isEmpty()
 	{
-#if CM_DEBUG_MODE
-		RenderSystem* rs = RenderSystemManager::getActive();
+		CM_LOCK_MUTEX(mCommandBufferMutex);
 
-		if(rs->getRenderThreadId() == CM_THREAD_CURRENT_ID)
-			CM_EXCEPT(InternalErrorException, "This method should never be called from the render thread as it will cause a deadlock.");
-#endif
+		if(mCommands != nullptr && mCommands->size() > 0)
+			return false;
 
-		{
-			CM_LOCK_MUTEX_NAMED(mCommandBufferMutex, lock);
-			while (mIsExecuting)
-			{
-				CM_THREAD_WAIT(mContextPlaybackDoneCondition, mCommandBufferMutex, lock)
-			}
-		}
+		return true;
 	}
 }

+ 2 - 2
CamelotRenderer/Source/CmGpuProgram.cpp

@@ -60,7 +60,7 @@ namespace CamelotEngine
 	//-----------------------------------------------------------------------------
 	void GpuProgram::initialize()
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&GpuProgram::initialize_internal, this));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&GpuProgram::initialize_internal, this));
 	}
     //-----------------------------------------------------------------------------
     void GpuProgram::initialize_internal(void)
@@ -126,7 +126,7 @@ namespace CamelotEngine
 	//---------------------------------------------------------------------
 	GpuProgramParametersSharedPtr GpuProgram::createParameters(void)
 	{
-		AsyncOp op = RenderSystemManager::getActive()->queueResourceReturnCommand(boost::bind(&GpuProgram::createParameters_internal, this, _1), true);
+		AsyncOp op = RenderSystemManager::getActive()->queueReturnCommand(boost::bind(&GpuProgram::createParameters_internal, this, _1), true);
 
 		return op.getReturnValue<GpuProgramParametersSharedPtr>();
 	}

+ 1 - 1
CamelotRenderer/Source/CmGpuProgramManager.cpp

@@ -45,7 +45,7 @@ namespace CamelotEngine {
 	//-------------------------------------------------------------------------
 	void GpuProgramManager::destroy(GpuProgram* program)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&GpuProgramManager::destroy_internal, this, program));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&GpuProgramManager::destroy_internal, this, program));
 	}
 	//-------------------------------------------------------------------------
 	void GpuProgramManager::destroy_internal(GpuProgram* program)

+ 1 - 1
CamelotRenderer/Source/CmHighLevelGpuProgram.cpp

@@ -52,7 +52,7 @@ namespace CamelotEngine
 	//---------------------------------------------------------------------------
 	void HighLevelGpuProgram::initialize()
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&HighLevelGpuProgram::initialize_internal, this));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&HighLevelGpuProgram::initialize_internal, this));
 	}
     //---------------------------------------------------------------------------
     void HighLevelGpuProgram::initialize_internal()

+ 1 - 1
CamelotRenderer/Source/CmHighLevelGpuProgramManager.cpp

@@ -136,7 +136,7 @@ namespace CamelotEngine {
 	//---------------------------------------------------------------------------
 	void HighLevelGpuProgramFactory::destroy(HighLevelGpuProgram* prog)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&HighLevelGpuProgramFactory::destroy_internal, this, prog));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&HighLevelGpuProgramFactory::destroy_internal, this, prog));
 	}
 	//---------------------------------------------------------------------
 	bool HighLevelGpuProgramManager::isLanguageSupported(const String& lang)

+ 3 - 3
CamelotRenderer/Source/CmMesh.cpp

@@ -36,7 +36,7 @@ namespace CamelotEngine
 
 	void Mesh::setMeshData(MeshDataPtr meshData)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Mesh::setMeshData_internal, this, meshData));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&Mesh::setMeshData_internal, this, meshData));
 	}
 
 	void Mesh::setMeshData_internal(MeshDataPtr meshData)
@@ -168,7 +168,7 @@ namespace CamelotEngine
 
 	MeshDataPtr Mesh::getMeshData()
 	{
-		AsyncOp op = RenderSystemManager::getActive()->queueResourceReturnCommand(boost::bind(&Mesh::getMeshData_internal, this, _1), true);
+		AsyncOp op = RenderSystemManager::getActive()->queueReturnCommand(boost::bind(&Mesh::getMeshData_internal, this, _1), true);
 
 		return op.getReturnValue<MeshDataPtr>();
 	}
@@ -306,7 +306,7 @@ namespace CamelotEngine
 	}
 	void Mesh::initialize()
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Mesh::initialize_internal, this));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&Mesh::initialize_internal, this));
 	}
 
 	void Mesh::initialize_internal()

+ 98 - 82
CamelotRenderer/Source/CmRenderSystem.cpp

@@ -41,6 +41,7 @@ THE SOFTWARE.
 #include "CmHardwareOcclusionQuery.h"
 #include "CmRenderSystemContext.h"
 #include "CmCommandQueue.h"
+#include "CmDeferredRenderContext.h"
 #include "boost/bind.hpp"
 
 #if CM_DEBUG_MODE
@@ -58,8 +59,6 @@ namespace CamelotEngine {
     //-----------------------------------------------------------------------
     RenderSystem::RenderSystem()
         : mActiveRenderTarget(0)
-        // This means CULL clockwise vertices, i.e. front of poly is counter-clockwise
-        // This makes it the same as OpenGL and other right-handed systems
         , mCullingMode(CULL_CLOCKWISE)
 		, mVsync(false)
 		, mVSyncInterval(1)
@@ -73,6 +72,7 @@ namespace CamelotEngine {
 		, mRenderThreadFunc(nullptr)
 		, mRenderThreadShutdown(false)
 		, mCommandQueue(nullptr)
+		, mMaxCommandNotifyId(0)
     {
     }
 
@@ -88,13 +88,13 @@ namespace CamelotEngine {
 	void RenderSystem::startUp()
 	{
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
-		mResourceContext = createResourceRenderSystemContext();
 		mPrimaryContext = createRenderSystemContext();
 		mActiveContext = mPrimaryContext;
+		mCommandQueue = new CommandQueue(CM_THREAD_CURRENT_ID);
 
 		initRenderThread();
 
-		queueResourceCommand(boost::bind(&RenderSystem::startUp_internal, this));
+		queueCommand(boost::bind(&RenderSystem::startUp_internal, this));
 	}
 	//-----------------------------------------------------------------------
 	void RenderSystem::startUp_internal()
@@ -104,13 +104,11 @@ namespace CamelotEngine {
 		mVertexProgramBound = false;
 		mGeometryProgramBound = false;
 		mFragmentProgramBound = false;
-
-		mCommandQueue = new CommandQueue(CM_THREAD_CURRENT_ID);
 	}
 	//-----------------------------------------------------------------------
 	void RenderSystem::shutdown(void)
 	{
-		queueResourceCommand(boost::bind(&RenderSystem::shutdown_internal, this), true);
+		queueCommand(boost::bind(&RenderSystem::shutdown_internal, this), true);
 		// TODO - What if something gets queued between these two calls?
 		shutdownRenderThread();
 	}
@@ -170,9 +168,9 @@ namespace CamelotEngine {
 		AsyncOp op;
 
 		if(miscParams != nullptr)
-			op = queueResourceReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, *miscParams, _1), true);
+			op = queueReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, *miscParams, _1), true);
 		else
-			op = queueResourceReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, NameValuePairList(), _1), true);
+			op = queueReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, NameValuePairList(), _1), true);
 
 		return op.getReturnValue<RenderWindow*>();
 	}
@@ -864,7 +862,7 @@ namespace CamelotEngine {
 		mRenderThread = t;
 
 		CM_LOCK_MUTEX_NAMED(mRSContextInitMutex, lock)
-		CM_THREAD_WAIT(mRSContextInitCondition, mRSContextInitMutex, lock)
+		CM_THREAD_WAIT(mRenderThreadStartCondition, mRSContextInitMutex, lock)
 
 #else
 		CM_EXCEPT(InternalErrorException, "Attempting to start a render thread but Camelot isn't compiled with thread support.");
@@ -875,40 +873,22 @@ namespace CamelotEngine {
 	{
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
 
-		CM_THREAD_NOTIFY_ALL(mRSContextInitCondition)
+		CM_THREAD_NOTIFY_ALL(mRenderThreadStartCondition)
 
 		while(true)
 		{
 			if(mRenderThreadShutdown)
 				return;
 
-			vector<RenderSystemContextPtr>::type renderSystemContextsCopy;
-			{
-				CM_LOCK_MUTEX(mRSContextMutex);
-
-				for(auto iter = mRenderSystemContexts.begin(); iter != mRenderSystemContexts.end(); ++iter)
-				{
-					renderSystemContextsCopy.push_back(*iter);
-				}
-			}
-
-
 			// Wait until we get some ready commands
+			vector<CommandQueue::Command>::type* commands = nullptr;
 			{
-				CM_LOCK_MUTEX_NAMED(mRSContextMutex, lock)
-
-				bool anyCommandsReady = false;
-				for(auto iter = renderSystemContextsCopy.begin(); iter != renderSystemContextsCopy.end(); ++iter)
-				{
-					if((*iter)->hasReadyCommands())
-					{
-						anyCommandsReady = true;
-						break;
-					}
-				}
+				CM_LOCK_MUTEX_NAMED(mCommandQueueMutex, lock)
 
-				if(!anyCommandsReady)
-					CM_THREAD_WAIT(mCommandReadyCondition, mRSContextMutex, lock)
+				while(mCommandQueue->isEmpty())
+					CM_THREAD_WAIT(mCommandReadyCondition, mCommandQueueMutex, lock)
+
+				commands = mCommandQueue->flush();
 			}
 
 			{
@@ -919,10 +899,7 @@ namespace CamelotEngine {
 			}
 
 			// Play commands
-			for(auto iter = renderSystemContextsCopy.begin(); iter != renderSystemContextsCopy.end(); ++iter)
-			{
-				(*iter)->playbackCommands();
-			}
+			mCommandQueue->playback(commands, boost::bind(&RenderSystem::commandCompletedNotify, this, _1)); 
 
 			{
 				CM_LOCK_MUTEX(mRSRenderCallbackMutex)
@@ -930,6 +907,8 @@ namespace CamelotEngine {
 				if(!PostRenderThreadUpdateCallback.empty())
 					PostRenderThreadUpdateCallback();
 			}
+
+			CM_THREAD_NOTIFY_ALL(mCommandQueueCompleteCondition);
 		}
 
 	}
@@ -956,25 +935,16 @@ namespace CamelotEngine {
 			);
 
 		{
-			CM_LOCK_MUTEX(mRSContextMutex);
+			CM_LOCK_MUTEX(mCommandQueueMutex);
 			mRenderSystemContexts.push_back(newContext);
 		}
 
 		return newContext;
 	}
 
-	RenderSystemContextPtr RenderSystem::createResourceRenderSystemContext()
+	DeferredRenderContextPtr RenderSystem::createDeferredContext()
 	{
-		RenderSystemContextPtr newContext = RenderSystemContextPtr(
-			new RenderSystemImmediateContext(CM_THREAD_CURRENT_ID)
-			);
-
-		{
-			CM_LOCK_MUTEX(mRSContextMutex);
-			mRenderSystemContexts.push_back(newContext);
-		}
-
-		return newContext;
+		return DeferredRenderContextPtr(new DeferredRenderContext(this, CM_THREAD_CURRENT_ID));
 	}
 
 	void RenderSystem::addPreRenderThreadUpdateCallback(boost::function<void()> callback)
@@ -997,7 +967,7 @@ namespace CamelotEngine {
 			CM_EXCEPT(InternalErrorException, "You are not allowed to call this method on the render thread!");
 
 		{
-			CM_LOCK_MUTEX(mRSContextMutex);
+			CM_LOCK_MUTEX(mCommandQueueMutex);
 
 			context->submitToGpu();
 		}
@@ -1016,49 +986,95 @@ namespace CamelotEngine {
 
 		mActiveContext = context;
 	}
-
-	AsyncOp RenderSystem::queueResourceReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete, UINT32 _callbackId)
-	{
-		AsyncOp op = mResourceContext->queueReturnCommand(commandCallback);
-		submitToGpu(mResourceContext, blockUntilComplete);
-
-		return op;
-	}
-
-	void RenderSystem::queueResourceCommand(boost::function<void()> commandCallback, bool blockUntilComplete, UINT32 _callbackId)
-	{
-		mResourceContext->queueCommand(commandCallback);
-		submitToGpu(mResourceContext, blockUntilComplete);
-	}
 	
-	AsyncOp RenderSystem::queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete, UINT32 _callbackId)
+	AsyncOp RenderSystem::queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete)
 	{
-		mCommandQueue->queueReturn(commandCallback, _callbackId);
-
 #ifdef CM_DEBUG_MODE
 		if(CM_THREAD_CURRENT_ID == getRenderThreadId())
 			CM_EXCEPT(InternalErrorException, "You are not allowed to call this method on the render thread!");
 #endif
 
+		AsyncOp op;
+		UINT32 commandId = -1;
+		{
+			CM_LOCK_MUTEX(mCommandQueueMutex);
+
+			if(blockUntilComplete)
+			{
+				commandId = mMaxCommandNotifyId++;
+				op = mCommandQueue->queueReturn(commandCallback, true, commandId);
+			}
+			else
+				op = mCommandQueue->queueReturn(commandCallback);
+		}
+
 		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition);
 
 		if(blockUntilComplete)
-			mCommandQueue->blockUntilExecuted();
+			blockUntilCommandCompleted(commandId);
+
+		return op;
 	}
 
-	void RenderSystem::queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete, UINT32 _callbackId)
+	void RenderSystem::queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete)
 	{
-		mCommandQueue->queue(commandCallback, _callbackId);
-
 #ifdef CM_DEBUG_MODE
 		if(CM_THREAD_CURRENT_ID == getRenderThreadId())
 			CM_EXCEPT(InternalErrorException, "You are not allowed to call this method on the render thread!");
 #endif
 
+		UINT32 commandId = -1;
+		{
+			CM_LOCK_MUTEX(mCommandQueueMutex);
+
+			if(blockUntilComplete)
+			{
+				commandId = mMaxCommandNotifyId++;
+				mCommandQueue->queue(commandCallback, true, commandId);
+			}
+			else
+				mCommandQueue->queue(commandCallback);
+		}
+
 		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition);
 
 		if(blockUntilComplete)
-			mCommandQueue->blockUntilExecuted();
+			blockUntilCommandCompleted(commandId);
+	}
+
+	void RenderSystem::blockUntilCommandCompleted(UINT32 commandId)
+	{
+		CM_LOCK_MUTEX_NAMED(mCommandNotifyMutex, lock);
+
+		while(true)
+		{
+			// Check if our command id is in the completed list
+			auto iter = mCommandsCompleted.begin();
+			for(; iter != mCommandsCompleted.end(); ++iter)
+			{
+				if(*iter == commandId)
+					break;
+			}
+
+			if(iter != mCommandsCompleted.end())
+			{
+				mCommandsCompleted.erase(iter);
+				break;
+			}
+
+			CM_THREAD_WAIT(mCommandQueueCompleteCondition, mCommandNotifyMutex, lock);
+		}
+	}
+
+	void RenderSystem::commandCompletedNotify(UINT32 commandId)
+	{
+		{
+			CM_LOCK_MUTEX(mCommandNotifyMutex);
+
+			mCommandsCompleted.push_back(commandId);
+		}
+
+		CM_THREAD_NOTIFY_ALL(mCommandCompleteCondition);
 	}
 
 	RenderSystemContextPtr RenderSystem::getActiveContext() const
@@ -1070,16 +1086,16 @@ namespace CamelotEngine {
 
 	void RenderSystem::update()
 	{
-		{
-			CM_LOCK_MUTEX(mRSContextMutex);
+		//{
+		//	CM_LOCK_MUTEX(mRSContextMutex);
 
-			for(auto iter = mRenderSystemContexts.begin(); iter != mRenderSystemContexts.end(); ++iter)
-			{
-				(*iter)->submitToGpu();
-			}
-		}
+		//	for(auto iter = mRenderSystemContexts.begin(); iter != mRenderSystemContexts.end(); ++iter)
+		//	{
+		//		(*iter)->submitToGpu();
+		//	}
+		//}
 
-		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition)
+		//CM_THREAD_NOTIFY_ALL(mCommandReadyCondition)
 	}
 
 	void RenderSystem::throwIfNotRenderThread() const

+ 1 - 1
CamelotRenderer/Source/CmRenderSystemManager.cpp

@@ -29,7 +29,7 @@ namespace CamelotEngine
 				if(newRenderSystem != nullptr)
 				{
 					if(mActiveRenderSystem != nullptr)
-						mActiveRenderSystem->shutdown_internal();
+						mActiveRenderSystem->shutdown();
 
 					mActiveRenderSystem = newRenderSystem;
 				}				

+ 5 - 5
CamelotRenderer/Source/CmTexture.cpp

@@ -74,7 +74,7 @@ namespace CamelotEngine {
 
 		mSize = getNumFaces() * PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
 
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Texture::initialize_internal, this));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&Texture::initialize_internal, this));
 	}
     //--------------------------------------------------------------------------
     bool Texture::hasAlpha(void) const
@@ -109,12 +109,12 @@ namespace CamelotEngine {
 
 	void Texture::setRawPixels(const PixelData& data, UINT32 face, UINT32 mip)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip), true);
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip), true);
 	}
 
 	void Texture::setRawPixels_async(const PixelData& data, UINT32 face, UINT32 mip)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&Texture::setRawPixels_internal, this, data, face, mip));
 	}
 
 	void Texture::setRawPixels_internal(const PixelData& data, UINT32 face, UINT32 mip)
@@ -143,14 +143,14 @@ namespace CamelotEngine {
 
 	PixelDataPtr Texture::getRawPixels(UINT32 face, UINT32 mip)
 	{
-		AsyncOp op = RenderSystemManager::getActive()->queueResourceReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1), true);
+		AsyncOp op = RenderSystemManager::getActive()->queueReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1), true);
 
 		return op.getReturnValue<PixelDataPtr>();
 	}
 
 	AsyncOp Texture::getRawPixels_async(UINT32 face, UINT32 mip)
 	{
-		return RenderSystemManager::getActive()->queueResourceReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1));
+		return RenderSystemManager::getActive()->queueReturnCommand(boost::bind(&Texture::getRawPixels_internal, this, face, mip, _1));
 	}
 
 	void Texture::getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op)

+ 1 - 1
CamelotRenderer/Source/CmTextureManager.cpp

@@ -45,7 +45,7 @@ namespace CamelotEngine {
 	//-----------------------------------------------------------------------
 	void TextureManager::destroy(Texture* texture)
 	{
-		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&TextureManager::destroy_internal, this, texture));
+		RenderSystemManager::getActive()->queueCommand(boost::bind(&TextureManager::destroy_internal, this, texture));
 	}
 	//-----------------------------------------------------------------------
 	void TextureManager::destroy_internal(Texture* texture)

+ 12 - 9
CamelotRenderer/TODO.txt

@@ -18,15 +18,18 @@
 
 /////
 First port (and test!) existing render systems so it is capable of dealing with DX11 stuff(samplerState, depthStencilState, rasterizerState objects primarily. Also split pass into Texture/sampler) 
-Also create immediate & deferred render context we can call render system methods on directly (immediate just calls render system using inline methods)
- - How to async call non-rendersystem methods? Like GpuProgram?? They either have to have contexts of their own (clumsy) or keep the like it is (separate method pairs, which is not the same interface
-   as the render system)
-Doublecheck the validity of resource and non-resource contexts
- - Calling a non-async resource method will block until the render thread is completely finished with its current task! (Is there a way to avoid that though?)
- - I need to define proper order of resource and render calls. What if a resource tries to get changed in the middle of a render call? It should only queue itself after
-   all previous command buffers are done executing.
-    - Whenever user does DeferredContext::submitCommands, all resource commands before that should get processed and only then should that command buffer be executed
- - Mutexes are slow as shit. Find a way to avoid them? (Primarily for resources, but check if we extensively used them elsewhere too)
+Render thread pre-post operations should just be queued into the global queue, instead of having actual hooks for those methods
+
+Add @copydoc documentation to DeferredRenderContext
+Delete CmRenderSystemContext
+Rename RenderSystem _internal methods
+Port RenderSystem so it uses the new mCommandQueue and remove obsolete methods
+
+
+
+
+Make CommandQueue not use mutexes and use atomics instead??
+Make sure that the simulation can't run faster then the render thread! (Block the main thread until previous render finishes)
 /////