ソースを参照

Hooked up some deferred rendering to application (currently not compilable)
Added more TODO stuff

Marko Pintera 13 年 前
コミット
1e218a6adc

+ 14 - 9
CamelotForwardRenderer/Source/CmForwardRenderer.cpp

@@ -7,6 +7,8 @@
 #include "CmMaterial.h"
 #include "CmMaterial.h"
 #include "CmMesh.h"
 #include "CmMesh.h"
 #include "CmPass.h"
 #include "CmPass.h"
+#include "CmApplication.h"
+#include "CmDeferredRenderSystem.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
@@ -25,13 +27,14 @@ namespace CamelotEngine
 
 
 	void ForwardRenderer::renderAll() 
 	void ForwardRenderer::renderAll() 
 	{
 	{
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
+		
+		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 
 
 		// TODO - No point in setting these each frame?
 		// TODO - No point in setting these each frame?
 		renderSystem->setInvertVertexWinding(false);
 		renderSystem->setInvertVertexWinding(false);
 		renderSystem->setDepthBufferParams();
 		renderSystem->setDepthBufferParams();
 
 
-
 		const vector<CameraPtr>::type& allCameras = gSceneManager().getAllCameras();
 		const vector<CameraPtr>::type& allCameras = gSceneManager().getAllCameras();
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
 		for(auto iter = allCameras.begin(); iter != allCameras.end(); ++iter)
 		{
 		{
@@ -45,7 +48,8 @@ namespace CamelotEngine
 	{
 	{
 		vector<RenderablePtr>::type allRenderables = gSceneManager().getVisibleRenderables(camera);
 		vector<RenderablePtr>::type allRenderables = gSceneManager().getVisibleRenderables(camera);
 
 
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
+		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 		renderSystem->setViewport(camera->getViewport());
 		renderSystem->setViewport(camera->getViewport());
 
 
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
@@ -96,7 +100,8 @@ namespace CamelotEngine
 
 
 		mActivePass = pass;
 		mActivePass = pass;
 
 
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
+		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 
 
 		GpuProgramRef vertProgram = pass->getVertexProgram();
 		GpuProgramRef vertProgram = pass->getVertexProgram();
 		if(vertProgram)
 		if(vertProgram)
@@ -200,22 +205,22 @@ namespace CamelotEngine
 	void ForwardRenderer::setPassParameters(PassParametersPtr params)
 	void ForwardRenderer::setPassParameters(PassParametersPtr params)
 	{
 	{
 		// TODO - When applying passes, don't re-apply states that are already the same as from previous pass.
 		// TODO - When applying passes, don't re-apply states that are already the same as from previous pass.
-
-		RenderSystem* renderSystem = RenderSystemManager::getActive();
+		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
+		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 
 
 		if(mActivePass == nullptr)
 		if(mActivePass == nullptr)
 			CM_EXCEPT(InternalErrorException, "Trying to set pass parameters, but no pass is set.");
 			CM_EXCEPT(InternalErrorException, "Trying to set pass parameters, but no pass is set.");
 
 
 		GpuProgramRef vertProgram = mActivePass->getVertexProgram();
 		GpuProgramRef vertProgram = mActivePass->getVertexProgram();
 		if(vertProgram)
 		if(vertProgram)
-			renderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, params->mVertParams, GPV_ALL);
+			renderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, params->mVertParams);
 
 
 		GpuProgramRef fragProgram = mActivePass->getFragmentProgram();
 		GpuProgramRef fragProgram = mActivePass->getFragmentProgram();
 		if(fragProgram)
 		if(fragProgram)
-			renderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, params->mFragParams, GPV_ALL);
+			renderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, params->mFragParams);
 
 
 		GpuProgramRef geomProgram = mActivePass->getGeometryProgram();
 		GpuProgramRef geomProgram = mActivePass->getGeometryProgram();
 		if(geomProgram)
 		if(geomProgram)
-			renderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, params->mGeomParams, GPV_ALL);
+			renderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, params->mGeomParams);
 	}
 	}
 }
 }

+ 6 - 3
CamelotRenderer/Include/CmApplication.h

@@ -26,8 +26,7 @@ namespace CamelotEngine
 
 
 			RenderWindow* getPrimaryRenderWindow() const { return mPrimaryRenderWindow; }
 			RenderWindow* getPrimaryRenderWindow() const { return mPrimaryRenderWindow; }
 
 
-			inline CM_THREAD_ID_TYPE getMainThreadId() const;
-			inline CM_THREAD_ID_TYPE getRenderThreadId() const;
+			DeferredRenderSystemPtr getActiveRenderSystem() const { return mPrimaryDeferredRenderSystem; }
 
 
 			/**
 			/**
 			 * @brief	Loads a plugin.
 			 * @brief	Loads a plugin.
@@ -38,8 +37,12 @@ namespace CamelotEngine
 
 
 	private:
 	private:
 		RenderWindow* mPrimaryRenderWindow;
 		RenderWindow* mPrimaryRenderWindow;
+		DeferredRenderSystemPtr mPrimaryDeferredRenderSystem;
 
 
-		CM_THREAD_ID_TYPE mRenderThreadId;
+		/**
+		 * @brief	Callback called from the render thread in order to initialize resources.
+		 */
+		void updateResourcesCallback();
 	};
 	};
 
 
 	CM_EXPORT Application& gApplication();
 	CM_EXPORT Application& gApplication();

+ 10 - 16
CamelotRenderer/Include/CmDeferredRenderSystem.h

@@ -283,15 +283,6 @@ namespace CamelotEngine
 			const Color& colour = Color::Black, 
 			const Color& colour = Color::Black, 
 			float depth = 1.0f, unsigned short stencil = 0);
 			float depth = 1.0f, unsigned short stencil = 0);
 
 
-		/**
-		 * @brief	Makes all the currently queued commands available to the GPU. They will be executed
-		 * 			as soon as the render thread is ready.
-		 * 			
-		 * @note	This is expected to be called once per frame. If the previous set of commands hasn't even started rendering
-		 * 			yet, it will be discarded. This is to prevent lag if the simulation executes faster than the render thread.
-		 */
-		void submitToGpu();
-
 	private:
 	private:
 		// Actively being filled up
 		// Actively being filled up
 		vector<DeferredGpuCommand*>::type* mActiveRenderCommandBuffer;
 		vector<DeferredGpuCommand*>::type* mActiveRenderCommandBuffer;
@@ -310,18 +301,12 @@ namespace CamelotEngine
 		 */
 		 */
 		void throwIfInvalidThread();
 		void throwIfInvalidThread();
 
 
-		/**
-		 * @brief	Called when there are some commands ready for processing. Usually meant to signal
-		 * 			the render thread.
-		 */
-		boost::function<void()> NotifyCommandsReady;
-
 		/************************************************************************/
 		/************************************************************************/
 		/* 					CALLABLE ONLY FROM RENDERSYSTEM                     */
 		/* 					CALLABLE ONLY FROM RENDERSYSTEM                     */
 		/************************************************************************/
 		/************************************************************************/
 		friend class RenderSystem;
 		friend class RenderSystem;
 
 
-		DeferredRenderSystem(CM_THREAD_ID_TYPE threadId, boost::function<void()> commandsReadyCallback);
+		DeferredRenderSystem(CM_THREAD_ID_TYPE threadId);
 
 
 		/**
 		/**
 		 * @brief	Plays all queued commands. Should only be called from the render thread,
 		 * @brief	Plays all queued commands. Should only be called from the render thread,
@@ -333,5 +318,14 @@ namespace CamelotEngine
 		 * @brief	Query if this object has any commands ready for rendering.
 		 * @brief	Query if this object has any commands ready for rendering.
 		 */
 		 */
 		bool hasReadyCommands();
 		bool hasReadyCommands();
+
+		/**
+		 * @brief	Makes all the currently queued commands available to the GPU. They will be executed
+		 * 			as soon as the render thread is ready.
+		 * 			
+		 * @note	This is expected to be called once per frame. If the previous set of commands hasn't even started rendering
+		 * 			yet, it will be discarded. This is to prevent lag if the simulation executes faster than the render thread.
+		 */
+		void submitToGpu();
 	};
 	};
 }
 }

+ 25 - 23
CamelotRenderer/Include/CmRenderSystem.h

@@ -45,6 +45,9 @@ THE SOFTWARE.
 #include "CmGpuProgram.h"
 #include "CmGpuProgram.h"
 #include "CmPlane.h"
 #include "CmPlane.h"
 
 
+#include "boost/function.hpp"
+#include "boost/signal.hpp"
+
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
 	/** \addtogroup Core
 	/** \addtogroup Core
@@ -296,7 +299,7 @@ namespace CamelotEngine
 			<td>Win32: HWND as integer<br/>
 			<td>Win32: HWND as integer<br/>
 			    GLX: poslong:posint:poslong (display*:screen:windowHandle) or poslong:posint:poslong:poslong (display*:screen:windowHandle:XVisualInfo*)</td>
 			    GLX: poslong:posint:poslong (display*:screen:windowHandle) or poslong:posint:poslong:poslong (display*:screen:windowHandle:XVisualInfo*)</td>
 			<td>0 (none)</td>
 			<td>0 (none)</td>
-			<td>Parent window handle, for embedding the OGRE in a child of an external window</td>
+			<td>Parent window handle, for embedding the engine in a child of an external window</td>
 			<td>&nbsp;</td>
 			<td>&nbsp;</td>
 		</tr>
 		</tr>
 		<tr>
 		<tr>
@@ -310,7 +313,7 @@ namespace CamelotEngine
 			<td>macAPICocoaUseNSView</td>
 			<td>macAPICocoaUseNSView</td>
 			<td>bool "true" or "false"</td>
 			<td>bool "true" or "false"</td>
 			<td>"false"</td>
 			<td>"false"</td>
-			<td>On the Mac platform the most diffused method to embed OGRE in a custom application is to use Interface Builder
+			<td>On the Mac platform the most diffused method to embed engine in a custom application is to use Interface Builder
 				and add to the interface an instance of OgreView.
 				and add to the interface an instance of OgreView.
 				The pointer to this instance is then used as "externalWindowHandle".
 				The pointer to this instance is then used as "externalWindowHandle".
 				However, there are cases where you are NOT using Interface Builder and you get the Cocoa NSView* of an existing interface.
 				However, there are cases where you are NOT using Interface Builder and you get the Cocoa NSView* of an existing interface.
@@ -320,17 +323,6 @@ namespace CamelotEngine
 			</td>
 			</td>
 			<td>&nbsp;</td>
 			<td>&nbsp;</td>
 		 </tr>
 		 </tr>
-         <tr>
-             <td>contentScalingFactor</td>
-             <td>Positive Float greater than 1.0</td>
-             <td>The default content scaling factor of the screen</td>
-             <td>Specifies the CAEAGLLayer content scaling factor.  Only supported on iOS 4 or greater.
-                 This can be useful to limit the resolution of the OpenGL ES backing store.  For example, the iPhone 4's
-                 native resolution is 960 x 640.  Windows are always 320 x 480, if you would like to limit the display
-                 to 720 x 480, specify 1.5 as the scaling factor.
-             </td>
-             <td>&nbsp;</td>
-		 </tr>
          <tr>
          <tr>
 			<td>FSAA</td>
 			<td>FSAA</td>
 			<td>Positive integer (usually 0, 2, 4, 8, 16)</td>
 			<td>Positive integer (usually 0, 2, 4, 8, 16)</td>
@@ -1054,12 +1046,15 @@ namespace CamelotEngine
 		CM_MUTEX(mDeferredRSInitMutex)
 		CM_MUTEX(mDeferredRSInitMutex)
 		CM_THREAD_SYNCHRONISER(mDeferredRSReadyCondition)
 		CM_THREAD_SYNCHRONISER(mDeferredRSReadyCondition)
 		CM_MUTEX(mDeferredRSMutex)
 		CM_MUTEX(mDeferredRSMutex)
+		CM_MUTEX(mDeferredRSCallbackMutex)
 
 
 #if CM_THREAD_SUPPORT
 #if CM_THREAD_SUPPORT
 		CM_THREAD_TYPE* mRenderThread;
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 #endif
 
 
 		vector<DeferredRenderSystemPtr>::type mDeferredRenderSystems;
 		vector<DeferredRenderSystemPtr>::type mDeferredRenderSystems;
+		boost::signal<void()> PreRenderThreadUpdateCallback;
+		boost::signal<void()> PostRenderThreadUpdateCallback;
 
 
 		/**
 		/**
 		 * @brief	Initializes a separate render thread. Should only be called once.
 		 * @brief	Initializes a separate render thread. Should only be called once.
@@ -1077,12 +1072,6 @@ namespace CamelotEngine
 		 */
 		 */
 		void shutdownRenderThread();
 		void shutdownRenderThread();
 
 
-		/**
-		 * @brief	Internal method that gets called by DeferredRenderSystems when 
-		 * 			they have commands ready for rendering.
-		 */
-		void notifyCommandsReadyCallback();
-
 		/**
 		/**
 		 * @brief	Throws an exception if current thread isn't the render thread;
 		 * @brief	Throws an exception if current thread isn't the render thread;
 		 */
 		 */
@@ -1101,12 +1090,25 @@ namespace CamelotEngine
 		 * 			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 deferred render system.
 		 * 			requires its own deferred render system.
-		 * 			
-		 * @remark	Be aware that creating a new deferred render system requires all active render commands
-		 * 			to complete, so it can potentially be a very slow operation as the thread will be blocked
-		 * 			until rendering is done.
 		 */
 		 */
 		DeferredRenderSystemPtr createDeferredRenderSystem();
 		DeferredRenderSystemPtr createDeferredRenderSystem();
+
+		/**
+		 * @brief	Callback that is called from the render thread before it starts processing
+		 * 			deferred render commands.
+		 */
+		void addPreRenderThreadUpdateCallback(boost::function<void()> callback);
+
+		/**
+		 * @brief	Callback that is called from the render thread after it ends processing
+		 * 			deferred render commands.
+		 */
+		void addPostRenderThreadUpdateCallback(boost::function<void()> callback);
+
+		/**
+		 * @brief	Called every frame
+		 */
+		void update();
 	};
 	};
 	/** @} */
 	/** @} */
 	/** @} */
 	/** @} */

+ 12 - 17
CamelotRenderer/Source/CmApplication.cpp

@@ -49,9 +49,11 @@ namespace CamelotEngine
 		RendererManager::setActive("ForwardRenderer");
 		RendererManager::setActive("ForwardRenderer");
 
 
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
-		renderSystem->startUp(false, false, "Camelot Renderer");
+		renderSystem->startUp(true, false, "Camelot Renderer");
+		renderSystem->addPreRenderThreadUpdateCallback(boost::bind(&Application::updateResourcesCallback, this));
 
 
-		mPrimaryRenderWindow = renderSystem->createRenderWindow("Camelot Renderer", 800, 600, false);
+		mPrimaryDeferredRenderSystem = renderSystem->createDeferredRenderSystem();
+		mPrimaryRenderWindow = renderSystem->createRenderWindow("Camelot Renderer", 1280, 720, false);
 
 
 		SceneManager::startUp(new SceneManager());
 		SceneManager::startUp(new SceneManager());
 		Resources::startUp(new Resources("D:\\CamelotResourceMetas"));
 		Resources::startUp(new Resources("D:\\CamelotResourceMetas"));
@@ -73,12 +75,19 @@ namespace CamelotEngine
 
 
 			RendererManager::getActive()->renderAll();
 			RendererManager::getActive()->renderAll();
 
 
+			RenderSystem* renderSystem = RenderSystemManager::getActive();
+			renderSystem->update();
+
 			gTime().update();
 			gTime().update();
 			gInput().update();
 			gInput().update();
-			gResources().update();
 		}
 		}
 	}
 	}
 
 
+	void Application::updateResourcesCallback()
+	{
+		gResources().update();
+	}
+
 	void Application::shutDown()
 	void Application::shutDown()
 	{
 	{
 		SceneManager::shutDown();
 		SceneManager::shutDown();
@@ -135,20 +144,6 @@ namespace CamelotEngine
 		return windowId;
 		return windowId;
 	}
 	}
 
 
-	CM_THREAD_ID_TYPE Application::getMainThreadId() const
-	{
-#if CM_THREAD_SUPPORT != 0
-		return CM_THREAD_CURRENT_ID;
-#else
-		return 0;
-#endif
-	}
-
-	CM_THREAD_ID_TYPE Application::getRenderThreadId() const
-	{
-		return mRenderThreadId;
-	}
-
 	Application& gApplication()
 	Application& gApplication()
 	{
 	{
 		static Application application;
 		static Application application;

+ 2 - 7
CamelotRenderer/Source/CmDeferredRenderSystem.cpp

@@ -5,8 +5,8 @@
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	DeferredRenderSystem::DeferredRenderSystem(CM_THREAD_ID_TYPE threadId, boost::function<void()> commandsReadyCallback)
-		:mMyThreadId(threadId), NotifyCommandsReady(commandsReadyCallback)
+	DeferredRenderSystem::DeferredRenderSystem(CM_THREAD_ID_TYPE threadId)
+		:mMyThreadId(threadId), mReadyRenderCommandBuffer(nullptr)
 	{
 	{
 		mActiveRenderCommandBuffer = new vector<DeferredGpuCommand*>::type();
 		mActiveRenderCommandBuffer = new vector<DeferredGpuCommand*>::type();
 	}
 	}
@@ -346,8 +346,6 @@ namespace CamelotEngine
 
 
 	void DeferredRenderSystem::submitToGpu()
 	void DeferredRenderSystem::submitToGpu()
 	{
 	{
-		throwIfInvalidThread();
-
 		{
 		{
 			CM_LOCK_MUTEX(mCommandBufferMutex)
 			CM_LOCK_MUTEX(mCommandBufferMutex)
 
 
@@ -362,9 +360,6 @@ namespace CamelotEngine
 
 
 			mReadyRenderCommandBuffer = mActiveRenderCommandBuffer;
 			mReadyRenderCommandBuffer = mActiveRenderCommandBuffer;
 			mActiveRenderCommandBuffer = new vector<DeferredGpuCommand*>::type();
 			mActiveRenderCommandBuffer = new vector<DeferredGpuCommand*>::type();
-
-			if(mReadyRenderCommandBuffer != nullptr && mReadyRenderCommandBuffer->size() > 0)
-				NotifyCommandsReady();
 		}
 		}
 	}
 	}
 
 

+ 68 - 13
CamelotRenderer/Source/CmRenderSystem.cpp

@@ -105,6 +105,9 @@ namespace CamelotEngine {
 		mGeometryProgramBound = false;
 		mGeometryProgramBound = false;
         mFragmentProgramBound = false;
         mFragmentProgramBound = false;
 
 
+		if(runOnSeparateThread)
+			initRenderThread();
+
         return 0;
         return 0;
     }
     }
 
 
@@ -555,13 +558,22 @@ namespace CamelotEngine {
 		{
 		{
 			if(mRenderThreadShutdown)
 			if(mRenderThreadShutdown)
 				return;
 				return;
-				
+
+			vector<DeferredRenderSystemPtr>::type deferredRenderSystemsCopy;
+			{
+				CM_LOCK_MUTEX(mDeferredRSMutex);
+
+				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
+					deferredRenderSystemsCopy.push_back(*iter);
+			}
+
+
 			// Wait until we get some ready commands
 			// Wait until we get some ready commands
 			{
 			{
 				CM_LOCK_MUTEX_NAMED(mDeferredRSMutex, lock)
 				CM_LOCK_MUTEX_NAMED(mDeferredRSMutex, lock)
 
 
 				bool anyCommandsReady = false;
 				bool anyCommandsReady = false;
-				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
+				for(auto iter = deferredRenderSystemsCopy.begin(); iter != deferredRenderSystemsCopy.end(); ++iter)
 				{
 				{
 					if((*iter)->hasReadyCommands())
 					if((*iter)->hasReadyCommands())
 					{
 					{
@@ -575,12 +587,23 @@ namespace CamelotEngine {
 			}
 			}
 
 
 			{
 			{
-				CM_LOCK_MUTEX(mDeferredRSMutex);
+				CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
 
 
-				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
-				{
-					(*iter)->playbackCommands();
-				}
+				if(!PreRenderThreadUpdateCallback.empty())
+					PreRenderThreadUpdateCallback();
+			}
+
+			// Play commands
+			for(auto iter = deferredRenderSystemsCopy.begin(); iter != deferredRenderSystemsCopy.end(); ++iter)
+			{
+				(*iter)->playbackCommands();
+			}
+
+			{
+				CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+
+				if(!PostRenderThreadUpdateCallback.empty())
+					PostRenderThreadUpdateCallback();
 			}
 			}
 		}
 		}
 
 
@@ -602,15 +625,15 @@ namespace CamelotEngine {
 		mDeferredRenderSystems.clear();
 		mDeferredRenderSystems.clear();
 	}
 	}
 
 
-	void RenderSystem::notifyCommandsReadyCallback()
-	{
-		CM_THREAD_NOTIFY_ALL(mDeferredRSReadyCondition)
-	}
-
 	DeferredRenderSystemPtr RenderSystem::createDeferredRenderSystem()
 	DeferredRenderSystemPtr RenderSystem::createDeferredRenderSystem()
 	{
 	{
+		if(!mUsingSeparateRenderThread)
+		{
+			CM_EXCEPT(InternalErrorException, "Cannot create deferred rendering system because separate render thread is not active.");
+		}
+
 		DeferredRenderSystemPtr newDeferredRS = DeferredRenderSystemPtr(
 		DeferredRenderSystemPtr newDeferredRS = DeferredRenderSystemPtr(
-			new DeferredRenderSystem(CM_THREAD_CURRENT_ID, boost::bind(&RenderSystem::notifyCommandsReadyCallback, this))
+			new DeferredRenderSystem(CM_THREAD_CURRENT_ID)
 			);
 			);
 
 
 		{
 		{
@@ -621,6 +644,38 @@ namespace CamelotEngine {
 		return newDeferredRS;
 		return newDeferredRS;
 	}
 	}
 
 
+	void RenderSystem::addPreRenderThreadUpdateCallback(boost::function<void()> callback)
+	{
+		CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+
+		PreRenderThreadUpdateCallback.connect(callback);
+	}
+
+	void RenderSystem::addPostRenderThreadUpdateCallback(boost::function<void()> callback)
+	{
+		CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+
+		PostRenderThreadUpdateCallback.connect(callback);
+	}
+
+	void RenderSystem::update()
+	{
+		if(mUsingSeparateRenderThread)
+		{
+			{
+				CM_LOCK_MUTEX(mDeferredRSMutex);
+
+				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
+				{
+					(*iter)->submitToGpu();
+				}
+			}
+
+			CM_THREAD_NOTIFY_ALL(mDeferredRSReadyCondition)
+		}
+
+	}
+
 	void RenderSystem::throwIfInvalidThread()
 	void RenderSystem::throwIfInvalidThread()
 	{
 	{
 		if(CM_THREAD_CURRENT_ID != getRenderThreadId())
 		if(CM_THREAD_CURRENT_ID != getRenderThreadId())

+ 11 - 7
CamelotRenderer/TODO.txt

@@ -16,20 +16,23 @@ High-level TODO:
 
 
 
 
 Command buffer TODO:
 Command buffer TODO:
-IMPORTANT:
- I can't just do CommandBuffer->setPass and expect it to work. User can modify the materials at any point before rendering happens, which will cause all kind of problems. I'll need to copy properties one by one.
-  - In order to avoid this, GpuParameters should return a copy of its physical data. (Similar to what Mesh->GetRenderOperation does). 
-  - Pass should return a copy of its own data as well.
-
 MAYBE:
 MAYBE:
  - Create DeferredRenderSystem class that has exactly the same public interface as RenderSystem, but defers all calls to a command buffer
  - Create DeferredRenderSystem class that has exactly the same public interface as RenderSystem, but defers all calls to a command buffer
    - As its methods are called we can also filter out values that exactly match the previous ones and minimize number of state changes
    - As its methods are called we can also filter out values that exactly match the previous ones and minimize number of state changes
       (Although this should probably be on a higher level, because 1 class 1 use)
       (Although this should probably be on a higher level, because 1 class 1 use)
 
 
+RESOURCE COMMANDS!!:
+ - They get queued up into the RenderSystem same like render commands
+ - They handle all resource creation/updates/destroy
+ - They are high level:
+   - i.e. CmndInitializeTexture - contains Texture to initialize and data to initialize it with
+ - This allows makes it possible not to store temporary texture or mesh data in the texture/mesh objects between initialization. The data is stored with the command instead.
+ - Also we don't need to handle resource loading in two steps. After loading is complete, resource gets queued up and initialized before next render frame.
+ - Make sure to clearly separate CPU and GPU commands on resources. Tell the user that GPU commands are deferred and will only be executed later. (Provide option to let him choose?)
+
 Essential TODO for deferred rendering:
 Essential TODO for deferred rendering:
  - Block all calls to RenderSystem outside of Render thread (or at least warn)
  - Block all calls to RenderSystem outside of Render thread (or at least warn)
  - Prevent user from accessing vertex/index buffers and similar outside of render thread as well (e.g. GpuProgram, Texture)
  - Prevent user from accessing vertex/index buffers and similar outside of render thread as well (e.g. GpuProgram, Texture)
- - Start render thread in application
 
 
  - Modify resource creation so it calls RenderContext and just schedules resource creation
  - Modify resource creation so it calls RenderContext and just schedules resource creation
 
 
@@ -86,7 +89,8 @@ Low priority TODO:
  - In RTTIType it is possible to add a non-plain data type using addPlainField. This can cause memory corruption issues
  - In RTTIType it is possible to add a non-plain data type using addPlainField. This can cause memory corruption issues
    if pointer is saved/loaded as a plain field. I need to add a check that ensures the type is POD. 
    if pointer is saved/loaded as a plain field. I need to add a check that ensures the type is POD. 
    See: http://www.boost.org/doc/libs/1_51_0/boost/mpi/datatype.hpp for a possible implementation of a compile time check.
    See: http://www.boost.org/doc/libs/1_51_0/boost/mpi/datatype.hpp for a possible implementation of a compile time check.
-
+ - Fix up WorkQueue as it doesn't lock when initializing, to make sure threads are actually started before returning
+ 
 Optional TODO:
 Optional TODO:
  - Add precompiled headers to all projects
  - Add precompiled headers to all projects
  - If possible, make sure GLSL uses EntryPoint and Profile fields I have added to GpuProgram
  - If possible, make sure GLSL uses EntryPoint and Profile fields I have added to GpuProgram