Browse Source

Tons of more work on multithreading for the render system

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

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -27,8 +27,8 @@ using namespace CamelotEngine;
 
 
 int _tmain(int argc, _TCHAR* argv[])
 int _tmain(int argc, _TCHAR* argv[])
 {
 {
-	gApplication().startUp("CamelotGLRenderSystem", "CamelotForwardRenderer");
-	//gApplication().startUp("CamelotD3D9RenderSystem", "CamelotForwardRenderer");
+	//gApplication().startUp("CamelotGLRenderSystem", "CamelotForwardRenderer");
+	gApplication().startUp("CamelotD3D9RenderSystem", "CamelotForwardRenderer");
 
 
 	RenderSystem* renderSystem = RenderSystemManager::getActive();
 	RenderSystem* renderSystem = RenderSystemManager::getActive();
 	RenderWindow* renderWindow = gApplication().getPrimaryRenderWindow();
 	RenderWindow* renderWindow = gApplication().getPrimaryRenderWindow();

+ 11 - 13
CamelotD3D9Renderer/Include/CmD3D9RenderSystem.h

@@ -182,18 +182,7 @@ namespace CamelotEngine
 
 
 		// Overridden RenderSystem functions
 		// Overridden RenderSystem functions
 		String validateConfigOptions();
 		String validateConfigOptions();
-		/**
-		 * @copydoc RenderSystem::startUp
-		 */
-		RenderWindow* startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle = "Camelot Render Window");
-		/// @copydoc RenderSystem::createRenderWindow
-		RenderWindow* createRenderWindow(const String &name, unsigned int width, unsigned int height, 
-			bool fullScreen, const NameValuePairList *miscParams = 0);
 		
 		
-		/// @copydoc RenderSystem::_createRenderWindows
-		bool _createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-			RenderWindowList& createdWindows);
-
 		/**
 		/**
          * Set current render target to target, enabling its GL context if needed
          * Set current render target to target, enabling its GL context if needed
          */
          */
@@ -229,7 +218,7 @@ namespace CamelotEngine
 		void setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendOperation op );
 		void setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendOperation op );
 		void setSeparateSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendFactor sourceFactorAlpha, SceneBlendFactor destFactorAlpha, SceneBlendOperation op, SceneBlendOperation alphaOp );
 		void setSeparateSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendFactor sourceFactorAlpha, SceneBlendFactor destFactorAlpha, SceneBlendOperation op, SceneBlendOperation alphaOp );
 		void setAlphaRejectSettings( CompareFunction func, unsigned char value, bool alphaToCoverage );
 		void setAlphaRejectSettings( CompareFunction func, unsigned char value, bool alphaToCoverage );
-		void setViewport( Viewport *vp );		
+		void setViewport(const Viewport& vp);		
 		void beginFrame();
 		void beginFrame();
 		void endFrame();		
 		void endFrame();		
 		void setCullingMode( CullingMode mode );
 		void setCullingMode( CullingMode mode );
@@ -249,7 +238,7 @@ namespace CamelotEngine
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
-        void bindGpuProgram(GpuProgram* prg);
+        void bindGpuProgram(GpuProgramRef prg);
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
@@ -312,6 +301,15 @@ namespace CamelotEngine
 		/// @copydoc RenderSystem::getDisplayMonitorCount
 		/// @copydoc RenderSystem::getDisplayMonitorCount
 		unsigned int getDisplayMonitorCount() const;
 		unsigned int getDisplayMonitorCount() const;
 		
 		
+		/************************************************************************/
+		/* 							INTERNAL CALLBACKS                     		*/
+		/************************************************************************/
+	protected:
+		void startUp_internal(AsyncOp& asyncOp);
+
+		void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
+			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp);
+
 	protected:	
 	protected:	
 		/// Notify when a device has been lost.
 		/// Notify when a device has been lost.
 		void notifyOnDeviceLost(D3D9Device* device);
 		void notifyOnDeviceLost(D3D9Device* device);

+ 1 - 1
CamelotD3D9Renderer/Source/CmD3D9DeviceManager.cpp

@@ -78,7 +78,7 @@ namespace CamelotEngine
 			}	
 			}	
 
 
 			// Invalidate active view port.
 			// Invalidate active view port.
-			renderSystem->mActiveViewport = NULL;
+			renderSystem->mActiveViewport = Viewport();
 		}						
 		}						
 	}
 	}
 
 

+ 157 - 272
CamelotD3D9Renderer/Source/CmD3D9RenderSystem.cpp

@@ -48,6 +48,7 @@ THE SOFTWARE.
 #include "CmD3D9DeviceManager.h"
 #include "CmD3D9DeviceManager.h"
 #include "CmD3D9ResourceManager.h"
 #include "CmD3D9ResourceManager.h"
 #include "CmHighLevelGpuProgramManager.h"
 #include "CmHighLevelGpuProgramManager.h"
+#include "CmAsyncOp.h"
 
 
 #define FLOAT2DWORD(f) *((DWORD*)&f)
 #define FLOAT2DWORD(f) *((DWORD*)&f)
 
 
@@ -72,34 +73,7 @@ namespace CamelotEngine
 		mHLSLProgramFactory = NULL;		
 		mHLSLProgramFactory = NULL;		
 		mCgProgramFactory = NULL;
 		mCgProgramFactory = NULL;
 		mDeviceManager = NULL;	
 		mDeviceManager = NULL;	
-
-		// Create the resource manager.
-		mResourceManager = new D3D9ResourceManager();
-
-		// Create our Direct3D object
-		if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
-			CM_EXCEPT(InternalErrorException, "Failed to create Direct3D9 object");
-
-		// set config options defaults
-		initConfigOptions();
-
-		// fsaa options
-		mFSAAHint = "";
-		mFSAASamples = 0;
-		
-		// set stages desc. to defaults
-		for (size_t n = 0; n < CM_MAX_TEXTURE_LAYERS; n++)
-		{
-			mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
-			mTexStageDesc[n].coordIndex = 0;
-			mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
-			mTexStageDesc[n].pTex = 0;
-			mTexStageDesc[n].pVertexTex = 0;
-		}
-
-		mLastVertexSourceCount = 0;
-
-		mCurrentLights.clear();			
+		mResourceManager = nullptr;		
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
 	D3D9RenderSystem::~D3D9RenderSystem()
 	D3D9RenderSystem::~D3D9RenderSystem()
@@ -483,122 +457,6 @@ namespace CamelotEngine
 		return StringUtil::BLANK;
 		return StringUtil::BLANK;
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
-	RenderWindow* D3D9RenderSystem::startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle )
-	{
-		RenderWindow* autoWindow = NULL;
-
-		// Init using current settings
-		mActiveD3DDriver = NULL;
-		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
-		for( UINT32 j=0; j < getDirect3DDrivers()->count(); j++ )
-		{
-			if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
-			{
-				mActiveD3DDriver = getDirect3DDrivers()->item(j);
-				break;
-			}
-		}
-
-		if( !mActiveD3DDriver )
-			CM_EXCEPT(InvalidParametersException, "Problems finding requested Direct3D driver!" );
-
-		// get driver version
-		mDriverVersion.major = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
-		mDriverVersion.minor = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
-		mDriverVersion.release = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
-		mDriverVersion.build = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
-
-		// Create the device manager.
-		mDeviceManager = new D3D9DeviceManager();
-
-		// Create the texture manager for use by others		
-		TextureManager::startUp(new D3D9TextureManager());
-
-		// Also create hardware buffer manager		
-		HardwareBufferManager::startUp(new D3D9HardwareBufferManager());
-
-		// Create the GPU program manager		
-		GpuProgramManager::startUp(new D3D9GpuProgramManager());
-
-		// Create & register HLSL factory		
-		mHLSLProgramFactory = new D3D9HLSLProgramFactory();
-		
-		// Create & register Cg factory		
-		mCgProgramFactory = new CgProgramFactory();
-
-		if( autoCreateWindow )
-		{
-			bool fullScreen;
-			opt = mOptions.find( "Full Screen" );
-			if( opt == mOptions.end() )
-				CM_EXCEPT(InternalErrorException, "Can't find full screen option!");
-			fullScreen = opt->second.currentValue == "Yes";
-
-			D3D9VideoMode* videoMode = NULL;
-			unsigned int width, height;
-			String temp;
-
-			opt = mOptions.find( "Video Mode" );
-			if( opt == mOptions.end() )
-				CM_EXCEPT(InternalErrorException, "Can't find Video Mode option!");
-
-			// The string we are manipulating looks like this :width x height @ colourDepth
-			// Pull out the colour depth by getting what comes after the @ and a space
-			String colourDepth = opt->second.currentValue.substr(opt->second.currentValue.rfind('@')+1);
-			// Now we know that the width starts a 0, so if we can find the end we can parse that out
-			String::size_type widthEnd = opt->second.currentValue.find(' ');
-			// we know that the height starts 3 characters after the width and goes until the next space
-			String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd+3);
-			// Now we can parse out the values
-			width = parseInt(opt->second.currentValue.substr(0, widthEnd));
-			height = parseInt(opt->second.currentValue.substr(widthEnd+3, heightEnd));
-
-			for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ )
-			{
-				temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription();
-
-				// In full screen we only want to allow supported resolutions, so temp and opt->second.currentValue need to 
-				// match exactly, but in windowed mode we can allow for arbitrary window sized, so we only need
-				// to match the colour values
-				if(fullScreen && (temp == opt->second.currentValue) ||
-					!fullScreen && (temp.substr(temp.rfind('@')+1) == colourDepth))
-				{
-					videoMode = mActiveD3DDriver->getVideoModeList()->item(j);
-					break;
-				}
-			}
-
-			if( !videoMode )
-				CM_EXCEPT(InternalErrorException, "Can't find requested video mode.");
-
-			// sRGB window option
-			bool hwGamma = false;
-
-			opt = mOptions.find( "sRGB Gamma Conversion" );
-			if( opt == mOptions.end() )
-				CM_EXCEPT(InternalErrorException, "Can't find sRGB option!");
-			hwGamma = opt->second.currentValue == "Yes";
-
-			NameValuePairList miscParams;
-			miscParams["colourDepth"] = toString(videoMode->getColourDepth());
-			miscParams["FSAA"] = toString(mFSAASamples);
-			miscParams["FSAAHint"] = mFSAAHint;
-			miscParams["vsync"] = toString(mVSync);
-			miscParams["vsyncInterval"] = toString(mVSyncInterval);
-			miscParams["useNVPerfHUD"] = toString(mUseNVPerfHUD);
-			miscParams["gamma"] = toString(hwGamma);
-			miscParams["monitorIndex"] = toString(static_cast<int>(mActiveD3DDriver->getAdapterNumber()));
-
-			autoWindow = createRenderWindow( windowTitle, width, height, 
-				fullScreen, &miscParams );
-		}	
-
-		// call superclass method
-		RenderSystem::startUp(runOnSeparateThread, autoCreateWindow);
-
-		return autoWindow;
-	}
-	//---------------------------------------------------------------------
 	void D3D9RenderSystem::shutdown()
 	void D3D9RenderSystem::shutdown()
 	{
 	{
 		RenderSystem::shutdown();
 		RenderSystem::shutdown();
@@ -612,96 +470,6 @@ namespace CamelotEngine
 		HardwareBufferManager::shutDown();
 		HardwareBufferManager::shutDown();
 		GpuProgramManager::shutDown();		
 		GpuProgramManager::shutDown();		
 	}
 	}
-	//---------------------------------------------------------------------
-	RenderWindow* D3D9RenderSystem::createRenderWindow(const String &name, 
-		unsigned int width, unsigned int height, bool fullScreen,
-		const NameValuePairList *miscParams)
-	{		
-		// Log a message
-		StringStream ss;
-		ss << "D3D9RenderSystem::_createRenderWindow \"" << name << "\", " <<
-			width << "x" << height << " ";
-		if(fullScreen)
-			ss << "fullscreen ";
-		else
-			ss << "windowed ";
-		if(miscParams)
-		{
-			ss << " miscParams: ";
-			NameValuePairList::const_iterator it;
-			for(it=miscParams->begin(); it!=miscParams->end(); ++it)
-			{
-				ss << it->first << "=" << it->second << " ";
-			}
-		}
-
-		String msg;
-
-		// Make sure we don't already have a render target of the 
-		// same name as the one supplied
-		if( mRenderTargets.find( name ) != mRenderTargets.end() )
-		{
-			msg = "A render target of the same name '" + name + "' already "
-				"exists.  You cannot create a new window with this name.";
-			CM_EXCEPT(InternalErrorException, msg);
-		}
-				
-		D3D9RenderWindow* renderWindow = new D3D9RenderWindow(mhInstance);
-		
-		renderWindow->create(name, width, height, fullScreen, miscParams);
-
-		mResourceManager->lockDeviceAccess();
-
-        try
-        {
-		    mDeviceManager->linkRenderWindow(renderWindow);
-        }
-        catch (const CamelotEngine::RenderingAPIException&)
-        {
-            // after catching the exception, clean up
-            mResourceManager->unlockDeviceAccess();
-            renderWindow->destroy();
-
-            // re-throw
-            throw;
-        }
-
-		mResourceManager->unlockDeviceAccess();
-	
-		mRenderWindows.push_back(renderWindow);		
-		
-		updateRenderSystemCapabilities(renderWindow);
-
-		attachRenderTarget( *renderWindow );
-		
-		return renderWindow;
-	}	
-	//---------------------------------------------------------------------
-	bool D3D9RenderSystem::_createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-		RenderWindowList& createdWindows)
-	{
-		// Call base render system method.
-		if (false == RenderSystem::_createRenderWindows(renderWindowDescriptions, createdWindows))
-			return false;
-
-		// Simply call _createRenderWindow in a loop.
-		for (size_t i = 0; i < renderWindowDescriptions.size(); ++i)
-		{
-			const RenderWindowDescription& curRenderWindowDescription = renderWindowDescriptions[i];			
-			RenderWindow* curWindow = NULL;
-
-			curWindow = createRenderWindow(curRenderWindowDescription.name, 
-				curRenderWindowDescription.width, 
-				curRenderWindowDescription.height, 
-				curRenderWindowDescription.useFullScreen, 
-				&curRenderWindowDescription.miscParams);
-							
-			createdWindows.push_back(curWindow);											
-		}
-		
-		return true;
-	}
-
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
 	RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow)
 	RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow)
 	{			
 	{			
@@ -2066,53 +1834,46 @@ namespace CamelotEngine
 		}
 		}
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
-	void D3D9RenderSystem::setViewport( Viewport *vp )
+	void D3D9RenderSystem::setViewport(const Viewport& vp)
 	{
 	{
-		if( vp != mActiveViewport)
-		{
-			mActiveViewport = vp;
+		mActiveViewport = vp;
 
 
-			// ok, it's different, time to set render target and viewport params
-			D3DVIEWPORT9 d3dvp;
-			HRESULT hr;
-
-			// Set render target
-			RenderTarget* target = vp->getTarget();
-			setRenderTarget(target);
+		// ok, it's different, time to set render target and viewport params
+		D3DVIEWPORT9 d3dvp;
+		HRESULT hr;
 
 
+		// Set render target
+		RenderTarget* target = vp.getTarget();
+		setRenderTarget(target);
 
 
-			setCullingMode( mCullingMode );
+		setCullingMode( mCullingMode );
 
 
-			// set viewport dimensions
-			d3dvp.X = vp->getActualLeft();
-			d3dvp.Y = vp->getActualTop();
-			d3dvp.Width = vp->getActualWidth();
-			d3dvp.Height = vp->getActualHeight();
-			if (target->requiresTextureFlipping())
-			{
-				// Convert "top-left" to "bottom-left"
-				d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
-			}
+		// set viewport dimensions
+		d3dvp.X = vp.getActualLeft();
+		d3dvp.Y = vp.getActualTop();
+		d3dvp.Width = vp.getActualWidth();
+		d3dvp.Height = vp.getActualHeight();
+		if (target->requiresTextureFlipping())
+		{
+			// Convert "top-left" to "bottom-left"
+			d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
+		}
 
 
-			// Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
-			d3dvp.MinZ = 0.0f;
-			d3dvp.MaxZ = 1.0f;
+		// Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
+		d3dvp.MinZ = 0.0f;
+		d3dvp.MaxZ = 1.0f;
 
 
-			if( FAILED( hr = getActiveD3D9Device()->SetViewport( &d3dvp ) ) )
-				CM_EXCEPT(RenderingAPIException, "Failed to set viewport.");
+		if( FAILED( hr = getActiveD3D9Device()->SetViewport( &d3dvp ) ) )
+			CM_EXCEPT(RenderingAPIException, "Failed to set viewport.");
 
 
-			// Set sRGB write mode
-			__SetRenderState(D3DRS_SRGBWRITEENABLE, target->isHardwareGammaEnabled());
-		}
+		// Set sRGB write mode
+		__SetRenderState(D3DRS_SRGBWRITEENABLE, target->isHardwareGammaEnabled());
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
 	void D3D9RenderSystem::beginFrame()
 	void D3D9RenderSystem::beginFrame()
 	{
 	{
 		HRESULT hr;
 		HRESULT hr;
 
 
-		if( !mActiveViewport )
-			CM_EXCEPT(InternalErrorException, "Cannot begin frame - no viewport selected.");
-
 		if( FAILED( hr = getActiveD3D9Device()->BeginScene() ) )
 		if( FAILED( hr = getActiveD3D9Device()->BeginScene() ) )
 		{
 		{
 			String msg = DXGetErrorDescription(hr);
 			String msg = DXGetErrorDescription(hr);
@@ -2322,14 +2083,16 @@ namespace CamelotEngine
 
 
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
-	void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg)
+	void D3D9RenderSystem::bindGpuProgram(GpuProgramRef prg)
 	{
 	{
+		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+
 		HRESULT hr;
 		HRESULT hr;
-		switch (prg->getType())
+		switch (bindingPrg->getType())
 		{
 		{
 		case GPT_VERTEX_PROGRAM:
 		case GPT_VERTEX_PROGRAM:
 			hr = getActiveD3D9Device()->SetVertexShader(
 			hr = getActiveD3D9Device()->SetVertexShader(
-				static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader());
+				static_cast<D3D9GpuVertexProgram*>(bindingPrg)->getVertexShader());
 			if (FAILED(hr))
 			if (FAILED(hr))
 			{
 			{
 				CM_EXCEPT(RenderingAPIException, "Error calling SetVertexShader");
 				CM_EXCEPT(RenderingAPIException, "Error calling SetVertexShader");
@@ -2337,7 +2100,7 @@ namespace CamelotEngine
 			break;
 			break;
 		case GPT_FRAGMENT_PROGRAM:
 		case GPT_FRAGMENT_PROGRAM:
 			hr = getActiveD3D9Device()->SetPixelShader(
 			hr = getActiveD3D9Device()->SetPixelShader(
-				static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader());
+				static_cast<D3D9GpuFragmentProgram*>(bindingPrg)->getPixelShader());
 			if (FAILED(hr))
 			if (FAILED(hr))
 			{
 			{
 				CM_EXCEPT(RenderingAPIException, "Error calling SetPixelShader");
 				CM_EXCEPT(RenderingAPIException, "Error calling SetPixelShader");
@@ -2925,7 +2688,7 @@ namespace CamelotEngine
 		// Restore previous active device.
 		// Restore previous active device.
 
 
 		// Invalidate active view port.
 		// Invalidate active view port.
-		mActiveViewport = NULL;
+		mActiveViewport = Viewport();
 
 
 		// Reset the texture stages, they will need to be rebound
 		// Reset the texture stages, they will need to be rebound
 		for (size_t i = 0; i < CM_MAX_TEXTURE_LAYERS; ++i)
 		for (size_t i = 0; i < CM_MAX_TEXTURE_LAYERS; ++i)
@@ -3080,5 +2843,127 @@ namespace CamelotEngine
 		} // while !ok
 		} // while !ok
 	}
 	}
 
 
+	/************************************************************************/
+	/* 							INTERNAL CALLBACKS                     		*/
+	/************************************************************************/
+	void D3D9RenderSystem::startUp_internal(AsyncOp& asyncOp)
+	{
+		// Create the resource manager.
+		mResourceManager = new D3D9ResourceManager();
+
+		// Create our Direct3D object
+		if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
+			CM_EXCEPT(InternalErrorException, "Failed to create Direct3D9 object");
+
+		// set config options defaults
+		initConfigOptions();
+
+		// fsaa options
+		mFSAAHint = "";
+		mFSAASamples = 0;
+
+		// set stages desc. to defaults
+		for (size_t n = 0; n < CM_MAX_TEXTURE_LAYERS; n++)
+		{
+			mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
+			mTexStageDesc[n].coordIndex = 0;
+			mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
+			mTexStageDesc[n].pTex = 0;
+			mTexStageDesc[n].pVertexTex = 0;
+		}
+
+		mLastVertexSourceCount = 0;
+
+		mCurrentLights.clear();	
+
+		RenderWindow* autoWindow = NULL;
+
+		// Init using current settings
+		mActiveD3DDriver = NULL;
+		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
+		for( UINT32 j=0; j < getDirect3DDrivers()->count(); j++ )
+		{
+			if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
+			{
+				mActiveD3DDriver = getDirect3DDrivers()->item(j);
+				break;
+			}
+		}
+
+		if( !mActiveD3DDriver )
+			CM_EXCEPT(InvalidParametersException, "Problems finding requested Direct3D driver!" );
+
+		// get driver version
+		mDriverVersion.major = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
+		mDriverVersion.minor = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
+		mDriverVersion.release = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
+		mDriverVersion.build = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
+
+		// Create the device manager.
+		mDeviceManager = new D3D9DeviceManager();
+
+		// Create the texture manager for use by others		
+		TextureManager::startUp(new D3D9TextureManager());
+
+		// Also create hardware buffer manager		
+		HardwareBufferManager::startUp(new D3D9HardwareBufferManager());
+
+		// Create the GPU program manager		
+		GpuProgramManager::startUp(new D3D9GpuProgramManager());
+
+		// Create & register HLSL factory		
+		mHLSLProgramFactory = new D3D9HLSLProgramFactory();
+
+		// Create & register Cg factory		
+		mCgProgramFactory = new CgProgramFactory();
+
+		// call superclass method
+		RenderSystem::startUp_internal(asyncOp);
+	}
+
+	void D3D9RenderSystem::createRenderWindow_internal(const String &name, 
+		unsigned int width, unsigned int height, bool fullScreen,
+		const NameValuePairList& miscParams, AsyncOp& asyncOp)
+	{		
+		String msg;
+
+		// Make sure we don't already have a render target of the 
+		// same name as the one supplied
+		if( mRenderTargets.find( name ) != mRenderTargets.end() )
+		{
+			msg = "A render target of the same name '" + name + "' already "
+				"exists.  You cannot create a new window with this name.";
+			CM_EXCEPT(InternalErrorException, msg);
+		}
+
+		D3D9RenderWindow* renderWindow = new D3D9RenderWindow(mhInstance);
+
+		renderWindow->create(name, width, height, fullScreen, &miscParams);
+
+		mResourceManager->lockDeviceAccess();
 
 
+		try
+		{
+			mDeviceManager->linkRenderWindow(renderWindow);
+		}
+		catch (const CamelotEngine::RenderingAPIException&)
+		{
+			// after catching the exception, clean up
+			mResourceManager->unlockDeviceAccess();
+			renderWindow->destroy();
+
+			// re-throw
+			throw;
+		}
+
+		mResourceManager->unlockDeviceAccess();
+
+		mRenderWindows.push_back(renderWindow);		
+
+		updateRenderSystemCapabilities(renderWindow);
+
+		attachRenderTarget( *renderWindow );
+
+		asyncOp.completeOperation(static_cast<RenderWindow*>(renderWindow));
+	}	
 }
 }

+ 9 - 7
CamelotForwardRenderer/Source/CmForwardRenderer.cpp

@@ -27,6 +27,8 @@ namespace CamelotEngine
 
 
 	void ForwardRenderer::renderAll() 
 	void ForwardRenderer::renderAll() 
 	{
 	{
+		return; // TODO - Temporarily I don't want to run this
+
 		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
 		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
 		
 		
 		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 		//RenderSystem* renderSystem = RenderSystemManager::getActive();
@@ -50,7 +52,7 @@ namespace CamelotEngine
 
 
 		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
 		DeferredRenderSystemPtr renderSystem = gApplication().getActiveRenderSystem();
 		//RenderSystem* renderSystem = RenderSystemManager::getActive();
 		//RenderSystem* renderSystem = RenderSystemManager::getActive();
-		renderSystem->setViewport(camera->getViewport());
+		renderSystem->setViewport(*camera->getViewport());
 
 
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 		Matrix4 viewMatrixCstm = camera->getViewMatrix();
@@ -106,33 +108,33 @@ namespace CamelotEngine
 		GpuProgramRef vertProgram = pass->getVertexProgram();
 		GpuProgramRef vertProgram = pass->getVertexProgram();
 		if(vertProgram)
 		if(vertProgram)
 		{
 		{
-			renderSystem->bindGpuProgram(vertProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgram(vertProgram);
 		}
 		}
 		else
 		else
 		{
 		{
-			if(renderSystem->isGpuProgramBound(GPT_VERTEX_PROGRAM))
+			//if(renderSystem->isGpuProgramBound(GPT_VERTEX_PROGRAM))
 				renderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
 				renderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
 		}
 		}
 
 
 		GpuProgramRef fragProgram = pass->getFragmentProgram();
 		GpuProgramRef fragProgram = pass->getFragmentProgram();
 		if(fragProgram)
 		if(fragProgram)
 		{
 		{
-			renderSystem->bindGpuProgram(fragProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgram(fragProgram);
 		}
 		}
 		else
 		else
 		{
 		{
-			if(renderSystem->isGpuProgramBound(GPT_FRAGMENT_PROGRAM))
+			//if(renderSystem->isGpuProgramBound(GPT_FRAGMENT_PROGRAM))
 				renderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 				renderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 		}
 		}
 
 
 		GpuProgramRef geomProgram = pass->getGeometryProgram();
 		GpuProgramRef geomProgram = pass->getGeometryProgram();
 		if(geomProgram)
 		if(geomProgram)
 		{
 		{
-			renderSystem->bindGpuProgram(geomProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgram(geomProgram);
 		}	
 		}	
 		else
 		else
 		{
 		{
-			if(renderSystem->isGpuProgramBound(GPT_GEOMETRY_PROGRAM))
+			//if(renderSystem->isGpuProgramBound(GPT_GEOMETRY_PROGRAM))
 				renderSystem->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 				renderSystem->unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 		}
 		}
 
 

+ 11 - 17
CamelotGLRenderer/Include/CmGLRenderSystem.h

@@ -75,8 +75,6 @@ namespace CamelotEngine {
 		GLint getTextureAddressingMode(SamplerState::TextureAddressingMode tam) const;
 		GLint getTextureAddressingMode(SamplerState::TextureAddressingMode tam) const;
 				void initialiseContext(RenderWindow* primary);
 				void initialiseContext(RenderWindow* primary);
 
 
-        void setLights();
-
         /// Store last depth write state
         /// Store last depth write state
         bool mDepthWrite;
         bool mDepthWrite;
 		/// Store last stencil mask state
 		/// Store last stencil mask state
@@ -120,6 +118,15 @@ namespace CamelotEngine {
 
 
 		UINT16 mActiveTextureUnit;
 		UINT16 mActiveTextureUnit;
 
 
+		/************************************************************************/
+		/* 							INTERNAL CALLBACKS                     		*/
+		/************************************************************************/
+	protected:
+        void startUp_internal(AsyncOp& asyncOp);
+
+		void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
+			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp);
+
 	protected:
 	protected:
 		void setClipPlanesImpl(const PlaneList& clipPlanes);
 		void setClipPlanesImpl(const PlaneList& clipPlanes);
 		bool activateGLTextureUnit(size_t unit);
 		bool activateGLTextureUnit(size_t unit);
@@ -147,10 +154,6 @@ namespace CamelotEngine {
           RenderSystem
           RenderSystem
          */
          */
         String validateConfigOptions(void);
         String validateConfigOptions(void);
-        /** See
-          RenderSystem
-         */
-        RenderWindow* startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle = "Camelot Render Window");
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
@@ -164,15 +167,6 @@ namespace CamelotEngine {
          */
          */
         void shutdown(void);
         void shutdown(void);
         
         
-		/// @copydoc RenderSystem::createRenderWindow
-		RenderWindow* createRenderWindow(const String &name, unsigned int width, unsigned int height, 
-			bool fullScreen, const NameValuePairList *miscParams = 0);
-
-		/// @copydoc RenderSystem::_createRenderWindows
-		bool _createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-			RenderWindowList& createdWindows);
-
-		
 		/// @copydoc RenderSystem::createMultiRenderTarget
 		/// @copydoc RenderSystem::createMultiRenderTarget
 		virtual MultiRenderTarget * createMultiRenderTarget(const String & name); 
 		virtual MultiRenderTarget * createMultiRenderTarget(const String & name); 
 		
 		
@@ -237,7 +231,7 @@ namespace CamelotEngine {
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
-        void setViewport(Viewport *vp);
+        void setViewport(const Viewport& vp);
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
@@ -327,7 +321,7 @@ namespace CamelotEngine {
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */
-        void bindGpuProgram(GpuProgram* prg);
+        void bindGpuProgram(GpuProgramRef prg);
         /** See
         /** See
           RenderSystem
           RenderSystem
          */
          */

+ 91 - 137
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -42,6 +42,7 @@ THE SOFTWARE.s
 #include "CmGLSLExtSupport.h"
 #include "CmGLSLExtSupport.h"
 #include "CmGLHardwareOcclusionQuery.h"
 #include "CmGLHardwareOcclusionQuery.h"
 #include "CmGLContext.h"
 #include "CmGLContext.h"
+#include "CmAsyncOp.h"
 
 
 #include "CmGLFBORenderTexture.h"
 #include "CmGLFBORenderTexture.h"
 #include "CmGLPBRenderTexture.h"
 #include "CmGLPBRenderTexture.h"
@@ -155,17 +156,6 @@ namespace CamelotEngine {
 		return mGLSupport->validateConfig();
 		return mGLSupport->validateConfig();
 	}
 	}
 
 
-	RenderWindow* GLRenderSystem::startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle)
-	{
-		mGLSupport->start();
-
-		RenderWindow* autoWindow = mGLSupport->createWindow(autoCreateWindow, this, windowTitle);
-
-		RenderSystem::startUp(runOnSeparateThread, autoCreateWindow, windowTitle);
-
-		return autoWindow;
-	}
-
 	RenderSystemCapabilities* GLRenderSystem::createRenderSystemCapabilities() const
 	RenderSystemCapabilities* GLRenderSystem::createRenderSystemCapabilities() const
 	{
 	{
 		RenderSystemCapabilities* rsc = new RenderSystemCapabilities();
 		RenderSystemCapabilities* rsc = new RenderSystemCapabilities();
@@ -916,83 +906,6 @@ namespace CamelotEngine {
 		//  the whole state.
 		//  the whole state.
 		mGLInitialised = 0;
 		mGLInitialised = 0;
 	}
 	}
-	//---------------------------------------------------------------------
-	bool GLRenderSystem::_createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-		RenderWindowList& createdWindows)
-	{		
-		// Call base render system method.
-		if (false == RenderSystem::_createRenderWindows(renderWindowDescriptions, createdWindows))
-			return false;
-
-		// Simply call _createRenderWindow in a loop.
-		for (size_t i = 0; i < renderWindowDescriptions.size(); ++i)
-		{
-			const RenderWindowDescription& curRenderWindowDescription = renderWindowDescriptions[i];			
-			RenderWindow* curWindow = NULL;
-
-			curWindow = createRenderWindow(curRenderWindowDescription.name, 
-				curRenderWindowDescription.width, 
-				curRenderWindowDescription.height, 
-				curRenderWindowDescription.useFullScreen, 
-				&curRenderWindowDescription.miscParams);
-
-			createdWindows.push_back(curWindow);											
-		}
-								
-		return true;
-	}
-	//---------------------------------------------------------------------
-	RenderWindow* GLRenderSystem::createRenderWindow(const String &name, 
-		unsigned int width, unsigned int height, bool fullScreen,
-		const NameValuePairList *miscParams)
-	{
-		if (mRenderTargets.find(name) != mRenderTargets.end())
-		{
-			CM_EXCEPT(InvalidParametersException, 
-				"Window with name '" + name + "' already exists");
-		}
-
-		// Create the window
-		RenderWindow* win = mGLSupport->newWindow(name, width, height, 
-			fullScreen, miscParams);
-
-		attachRenderTarget( *win );
-
-		if (!mGLInitialised) 
-		{                
-
-			// set up glew and GLSupport
-			initialiseContext(win);
-
-			std::vector<CamelotEngine::String> tokens = StringUtil::split(mGLSupport->getGLVersion(), ".");
-
-			if (!tokens.empty())
-			{
-				mDriverVersion.major = parseInt(tokens[0]);
-				if (tokens.size() > 1)
-					mDriverVersion.minor = parseInt(tokens[1]);
-				if (tokens.size() > 2)
-					mDriverVersion.release = parseInt(tokens[2]); 
-			}
-			mDriverVersion.build = 0;
-			// Initialise GL after the first window has been created
-			// TODO: fire this from emulation options, and don't duplicate float and Current capabilities
-			mRealCapabilities = createRenderSystemCapabilities();
-
-			// use real capabilities if custom capabilities are not available
-			if(!mUseCustomCapabilities)
-				mCurrentCapabilities = mRealCapabilities;
-
-			initialiseFromRenderSystemCapabilities(mCurrentCapabilities, win);
-
-			// Initialise the main context
-			_oneTimeContextInitialization();
-			if(mCurrentContext)
-				mCurrentContext->setInitialized();
-		}
-
-		return win;
-	}
 
 
 	void GLRenderSystem::initialiseContext(RenderWindow* primary)
 	void GLRenderSystem::initialiseContext(RenderWindow* primary)
 	{
 	{
@@ -1068,12 +981,12 @@ namespace CamelotEngine {
 			// independent size if you're looking for attenuation.
 			// independent size if you're looking for attenuation.
 			// So, scale the point size up by viewport size (this is equivalent to
 			// So, scale the point size up by viewport size (this is equivalent to
 			// what D3D does as standard)
 			// what D3D does as standard)
-			size = size * mActiveViewport->getActualHeight();
-			minSize = minSize * mActiveViewport->getActualHeight();
+			size = size * mActiveViewport.getActualHeight();
+			minSize = minSize * mActiveViewport.getActualHeight();
 			if (maxSize == 0.0f)
 			if (maxSize == 0.0f)
 				maxSize = mCurrentCapabilities->getMaxPointSize(); // pixels
 				maxSize = mCurrentCapabilities->getMaxPointSize(); // pixels
 			else
 			else
-				maxSize = maxSize * mActiveViewport->getActualHeight();
+				maxSize = maxSize * mActiveViewport.getActualHeight();
 			
 			
 			// XXX: why do I need this for results to be consistent with D3D?
 			// XXX: why do I need this for results to be consistent with D3D?
 			// Equations are supposedly the same once you factor in vp height
 			// Equations are supposedly the same once you factor in vp height
@@ -1405,55 +1318,34 @@ namespace CamelotEngine {
 
 
 	}
 	}
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
-	void GLRenderSystem::setViewport(Viewport *vp)
+	void GLRenderSystem::setViewport(const Viewport& vp)
 	{
 	{
-		// Check if viewport is different
-		if (vp != mActiveViewport)
-		{
-			RenderTarget* target;
-			target = vp->getTarget();
-			setRenderTarget(target);
-			mActiveViewport = vp;
-
-			GLsizei x, y, w, h;
+		RenderTarget* target;
+		target = vp.getTarget();
+		setRenderTarget(target);
+		mActiveViewport = vp;
 
 
-			// Calculate the "lower-left" corner of the viewport
-			w = vp->getActualWidth();
-			h = vp->getActualHeight();
-			x = vp->getActualLeft();
-			y = vp->getActualTop();
-			if (!target->requiresTextureFlipping())
-			{
-				// Convert "upper-left" corner to "lower-left"
-				y = target->getHeight() - h - y;
-			}
-			glViewport(x, y, w, h);
+		GLsizei x, y, w, h;
 
 
-			// Configure the viewport clipping
-			glScissor(x, y, w, h);
+		// Calculate the "lower-left" corner of the viewport
+		w = vp.getActualWidth();
+		h = vp.getActualHeight();
+		x = vp.getActualLeft();
+		y = vp.getActualTop();
+		if (!target->requiresTextureFlipping())
+		{
+			// Convert "upper-left" corner to "lower-left"
+			y = target->getHeight() - h - y;
 		}
 		}
-	}
+		glViewport(x, y, w, h);
 
 
-	void GLRenderSystem::setLights()
-	{
-		// TODO PORT - I'm not using fixed pipeline lights. Remove this later
-		//for (size_t i = 0; i < MAX_LIGHTS; ++i)
-		//{
-		//	if (mLights[i] != NULL)
-		//	{
-		//		Light* lt = mLights[i];
-		//		setGLLightPositionDirection(lt, GL_LIGHT0 + i);
-		//	}
-		//}
+		// Configure the viewport clipping
+		glScissor(x, y, w, h);
 	}
 	}
 
 
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	void GLRenderSystem::beginFrame(void)
 	void GLRenderSystem::beginFrame(void)
 	{
 	{
-		if (!mActiveViewport)
-			CM_EXCEPT(InvalidStateException, 
-			"Cannot begin frame - no viewport selected.");
-
 		// Activate the viewport clipping
 		// Activate the viewport clipping
 		glEnable(GL_SCISSOR_TEST);
 		glEnable(GL_SCISSOR_TEST);
 	}
 	}
@@ -2121,9 +2013,10 @@ namespace CamelotEngine {
 
 
 	}
 	}
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
-	void GLRenderSystem::bindGpuProgram(GpuProgram* prg)
+	void GLRenderSystem::bindGpuProgram(GpuProgramRef prg)
 	{
 	{
-		GLGpuProgram* glprg = static_cast<GLGpuProgram*>(prg);
+		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+		GLGpuProgram* glprg = static_cast<GLGpuProgram*>(bindingPrg);
 
 
 		// Unbind previous gpu program first.
 		// Unbind previous gpu program first.
 		//
 		//
@@ -2321,13 +2214,13 @@ namespace CamelotEngine {
 		{
 		{
 			glDisable(GL_SCISSOR_TEST);
 			glDisable(GL_SCISSOR_TEST);
 			// GL requires you to reset the scissor when disabling
 			// GL requires you to reset the scissor when disabling
-			w = mActiveViewport->getActualWidth();
-			h = mActiveViewport->getActualHeight();
-			x = mActiveViewport->getActualLeft();
+			w = mActiveViewport.getActualWidth();
+			h = mActiveViewport.getActualHeight();
+			x = mActiveViewport.getActualLeft();
 			if (flipping)
 			if (flipping)
-				y = mActiveViewport->getActualTop();
+				y = mActiveViewport.getActualTop();
 			else
 			else
-				y = targetHeight - mActiveViewport->getActualTop() - h;
+				y = targetHeight - mActiveViewport.getActualTop() - h;
 			glScissor(x, y, w, h);
 			glScissor(x, y, w, h);
 		}
 		}
 	}
 	}
@@ -2637,5 +2530,66 @@ namespace CamelotEngine {
 		return mGLSupport->getDisplayMonitorCount();
 		return mGLSupport->getDisplayMonitorCount();
 	}
 	}
 
 
+	/************************************************************************/
+	/* 							INTERNAL CALLBACKS                     		*/
+	/************************************************************************/
+
+	void GLRenderSystem::startUp_internal(AsyncOp& asyncOp)
+	{
+		mGLSupport->start();
+
+		RenderSystem::startUp_internal(asyncOp);
+	}
+
+	void GLRenderSystem::createRenderWindow_internal(const String &name, 
+		unsigned int width, unsigned int height, bool fullScreen,
+		const NameValuePairList& miscParams, AsyncOp& asyncOp)
+	{
+		if (mRenderTargets.find(name) != mRenderTargets.end())
+		{
+			CM_EXCEPT(InvalidParametersException, 
+				"Window with name '" + name + "' already exists");
+		}
+
+		// Create the window
+		RenderWindow* win = mGLSupport->newWindow(name, width, height, 
+			fullScreen, &miscParams);
+
+		attachRenderTarget( *win );
+
+		if (!mGLInitialised) 
+		{                
+
+			// set up glew and GLSupport
+			initialiseContext(win);
+
+			std::vector<CamelotEngine::String> tokens = StringUtil::split(mGLSupport->getGLVersion(), ".");
 
 
+			if (!tokens.empty())
+			{
+				mDriverVersion.major = parseInt(tokens[0]);
+				if (tokens.size() > 1)
+					mDriverVersion.minor = parseInt(tokens[1]);
+				if (tokens.size() > 2)
+					mDriverVersion.release = parseInt(tokens[2]); 
+			}
+			mDriverVersion.build = 0;
+			// Initialise GL after the first window has been created
+			// TODO: fire this from emulation options, and don't duplicate float and Current capabilities
+			mRealCapabilities = createRenderSystemCapabilities();
+
+			// use real capabilities if custom capabilities are not available
+			if(!mUseCustomCapabilities)
+				mCurrentCapabilities = mRealCapabilities;
+
+			initialiseFromRenderSystemCapabilities(mCurrentCapabilities, win);
+
+			// Initialise the main context
+			_oneTimeContextInitialization();
+			if(mCurrentContext)
+				mCurrentContext->setInitialized();
+		}
+
+		asyncOp.completeOperation(win);
+	}
 }
 }

+ 2 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -138,6 +138,7 @@
     <ClInclude Include="Include\CmRenderOperation.h" />
     <ClInclude Include="Include\CmRenderOperation.h" />
     <ClInclude Include="Include\CmRenderSystem.h" />
     <ClInclude Include="Include\CmRenderSystem.h" />
     <ClInclude Include="Include\CmRenderSystemCapabilities.h" />
     <ClInclude Include="Include\CmRenderSystemCapabilities.h" />
+    <ClInclude Include="Include\CmRenderSystemContext.h" />
     <ClInclude Include="Include\CmRenderSystemFactory.h" />
     <ClInclude Include="Include\CmRenderSystemFactory.h" />
     <ClInclude Include="Include\CmRenderSystemManager.h" />
     <ClInclude Include="Include\CmRenderSystemManager.h" />
     <ClInclude Include="Include\CmRenderTarget.h" />
     <ClInclude Include="Include\CmRenderTarget.h" />
@@ -199,6 +200,7 @@
     <ClCompile Include="Source\CmRendererManager.cpp" />
     <ClCompile Include="Source\CmRendererManager.cpp" />
     <ClCompile Include="Source\CmRenderSystem.cpp" />
     <ClCompile Include="Source\CmRenderSystem.cpp" />
     <ClCompile Include="Source\CmRenderSystemCapabilities.cpp" />
     <ClCompile Include="Source\CmRenderSystemCapabilities.cpp" />
+    <ClCompile Include="Source\CmRenderSystemContext.cpp" />
     <ClCompile Include="Source\CmRenderSystemManager.cpp" />
     <ClCompile Include="Source\CmRenderSystemManager.cpp" />
     <ClCompile Include="Source\CmRenderTarget.cpp" />
     <ClCompile Include="Source\CmRenderTarget.cpp" />
     <ClCompile Include="Source\CmRenderTexture.cpp" />
     <ClCompile Include="Source\CmRenderTexture.cpp" />

+ 6 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -313,6 +313,9 @@
     <ClInclude Include="Include\CmDeferredGpuCommands.h">
     <ClInclude Include="Include\CmDeferredGpuCommands.h">
       <Filter>Header Files\RenderSystem</Filter>
       <Filter>Header Files\RenderSystem</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmRenderSystemContext.h">
+      <Filter>Header Files\RenderSystem</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
     <ClCompile Include="Source\CamelotRenderer.cpp">
@@ -462,5 +465,8 @@
     <ClCompile Include="Source\CmDeferredGpuCommands.cpp">
     <ClCompile Include="Source\CmDeferredGpuCommands.cpp">
       <Filter>Source Files\RenderSystem</Filter>
       <Filter>Source Files\RenderSystem</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmRenderSystemContext.cpp">
+      <Filter>Source Files\RenderSystem</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 33 - 3
CamelotRenderer/Include/CmDeferredGpuCommands.h

@@ -13,6 +13,14 @@ namespace CamelotEngine
 		virtual void submitCommand(RenderSystem* rs) = 0;
 		virtual void submitCommand(RenderSystem* rs) = 0;
 	};
 	};
 
 
+	class CM_EXPORT DfrdRSStartUpCommand : public DeferredGpuCommand
+	{
+	public:
+		DfrdRSStartUpCommand();
+
+		virtual void submitCommand(RenderSystem* rs);
+	};
+
 	class CM_EXPORT DfrdRenderGpuCommand : public DeferredGpuCommand
 	class CM_EXPORT DfrdRenderGpuCommand : public DeferredGpuCommand
 	{
 	{
 	public:
 	public:
@@ -26,9 +34,19 @@ namespace CamelotEngine
 	class CM_EXPORT DfrdBindGpuProgramCommand : public DeferredGpuCommand
 	class CM_EXPORT DfrdBindGpuProgramCommand : public DeferredGpuCommand
 	{
 	{
 	public:
 	public:
-		DfrdBindGpuProgramCommand(GpuProgramPtr _gpuProgram);
+		DfrdBindGpuProgramCommand(GpuProgramRef _gpuProgram);
+
+		GpuProgramRef gpuProgram;
+
+		virtual void submitCommand(RenderSystem* rs);
+	};
+
+	class CM_EXPORT DfrdUnbindGpuProgramCommand : public DeferredGpuCommand
+	{
+	public:
+		DfrdUnbindGpuProgramCommand(GpuProgramType _type);
 
 
-		GpuProgramPtr gpuProgram;
+		GpuProgramType type;
 
 
 		virtual void submitCommand(RenderSystem* rs);
 		virtual void submitCommand(RenderSystem* rs);
 	};
 	};
@@ -291,7 +309,9 @@ namespace CamelotEngine
 	class CM_EXPORT DfrdViewportCommand : public DeferredGpuCommand
 	class CM_EXPORT DfrdViewportCommand : public DeferredGpuCommand
 	{
 	{
 	public:
 	public:
-		DfrdViewportCommand();
+		DfrdViewportCommand(const Viewport& _vp);
+
+		Viewport vp;
 
 
 		virtual void submitCommand(RenderSystem* rs);
 		virtual void submitCommand(RenderSystem* rs);
 	};
 	};
@@ -422,4 +442,14 @@ namespace CamelotEngine
 
 
 		virtual void submitCommand(RenderSystem* rs);
 		virtual void submitCommand(RenderSystem* rs);
 	};
 	};
+
+	class CM_EXPORT DfrdSwapAllRenderTargetBuffersCommand : public DeferredGpuCommand
+	{
+	public:
+		DfrdSwapAllRenderTargetBuffersCommand(bool _waitForVsync);
+
+		bool waitForVsync;
+
+		virtual void submitCommand(RenderSystem* rs);
+	};
 }
 }

+ 16 - 2
CamelotRenderer/Include/CmDeferredRenderSystem.h

@@ -25,7 +25,14 @@ namespace CamelotEngine
 		 * 			
 		 * 			
 		 * @see		RenderSystem::bindGpuProgram()
 		 * @see		RenderSystem::bindGpuProgram()
 		 */
 		 */
-		virtual void bindGpuProgram(GpuProgramPtr prg);
+		void bindGpuProgram(GpuProgramRef prg);
+
+		/**
+		 * @brief	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
+		 * 			
+		 * @see		RenderSystem::unbindGpuProgram()
+		 */
+		void unbindGpuProgram(GpuProgramType gptype);
 
 
 		/**
 		/**
 		 * @brief	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
 		 * @brief	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
@@ -195,7 +202,7 @@ namespace CamelotEngine
 		 * 			
 		 * 			
 		 * @see		RenderSystem::setViewport()
 		 * @see		RenderSystem::setViewport()
 		 */
 		 */
-		void setViewport(Viewport *vp);
+		void setViewport(const Viewport& vp);
 		
 		
 		/**
 		/**
 		 * @brief	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
 		 * @brief	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
@@ -283,6 +290,13 @@ 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	Wrapper around RenderSystem method of the same name. See RenderSystem doc.
+		 * 			
+		 * @see		RenderSystem::swapAllRenderTargetBuffers()
+		 */
+		void swapAllRenderTargetBuffers(bool waitForVsync = true);
+
 	private:
 	private:
 		// Actively being filled up
 		// Actively being filled up
 		vector<DeferredGpuCommand*>::type* mActiveRenderCommandBuffer;
 		vector<DeferredGpuCommand*>::type* mActiveRenderCommandBuffer;

+ 3 - 0
CamelotRenderer/Include/CmPrerequisites.h

@@ -107,6 +107,8 @@ namespace CamelotEngine {
 	class PassParameters;
 	class PassParameters;
 	class DeferredRenderSystem;
 	class DeferredRenderSystem;
 	class DeferredGpuCommand;
 	class DeferredGpuCommand;
+	class RenderSystemContext;
+	class AsyncOp;
 	// Asset import
 	// Asset import
 	class SpecificImporter;
 	class SpecificImporter;
 	class Importer;
 	class Importer;
@@ -145,6 +147,7 @@ namespace CamelotEngine
 	typedef std::shared_ptr<WorkQueue> WorkQueuePtr;
 	typedef std::shared_ptr<WorkQueue> WorkQueuePtr;
 	typedef std::shared_ptr<PassParameters> PassParametersPtr;
 	typedef std::shared_ptr<PassParameters> PassParametersPtr;
 	typedef std::shared_ptr<DeferredRenderSystem> DeferredRenderSystemPtr;
 	typedef std::shared_ptr<DeferredRenderSystem> DeferredRenderSystemPtr;
+	typedef std::shared_ptr<RenderSystemContext> RenderSystemContextPtr;
 
 
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<GameObject> GameObjectPtr;
 	typedef std::shared_ptr<GameObject> GameObjectPtr;

+ 44 - 54
CamelotRenderer/Include/CmRenderSystem.h

@@ -162,24 +162,14 @@ namespace CamelotEngine
 		*/
 		*/
 		virtual String validateConfigOptions(void) = 0;
 		virtual String validateConfigOptions(void) = 0;
 
 
-		/** Start up the renderer using the settings selected (Or the defaults if none have been selected).
-		@param
-		runOnSeparateThread 
-		If true, a separate internal render thread will be created, and you will only be allowed to call RenderSystem methods
-		from DeferredRenderSystem created by RenderSystem::createDeferred().
-		@param
-		autoCreateWindow If true, creates a render window
-		automatically, based on settings chosen so far. This saves
-		an extra call to _createRenderWindow
-		for the main render window.
-		@par
-		If an application has more specific window requirements,
-		however (e.g. a level design app), it should specify false
-		for this parameter and do it manually.
-		@returns
-		A pointer to the automatically created window, if requested, otherwise null.
-		*/
-		virtual RenderWindow* startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle = "Camelot Render Window");
+		 /* @brief	Start up the RenderSystem. Call before doing any operations on the render system.  
+		 *			Make sure all subsequent calls to the RenderSystem are done from the same thread it was started on.  
+		 *
+		 * @remark	If you want to access the render system from other threads, call RenderSystem::createRenderContext,
+		 * 			set the active context using RenderSystem::setActiveRenderContext and call the render system normally.
+		 * 			By default an automatically created primary render context is used.
+		 */
+		void startUp();
 
 
 
 
 		/** Query the real capabilities of the GPU and driver in the RenderSystem*/
 		/** Query the real capabilities of the GPU and driver in the RenderSystem*/
@@ -392,27 +382,8 @@ namespace CamelotEngine
 			<td>&nbsp;</td>
 			<td>&nbsp;</td>
 		</tr>
 		</tr>
 		*/
 		*/
-		virtual RenderWindow* createRenderWindow(const String &name, unsigned int width, unsigned int height, 
-			bool fullScreen, const NameValuePairList *miscParams = 0) = 0;
-
-		/** Creates multiple rendering windows.		
-		@param
-		renderWindowDescriptions Array of structures containing the descriptions of each render window.
-		The structure's members are the same as the parameters of _createRenderWindow:
-		* name
-		* width
-		* height
-		* fullScreen
-		* miscParams
-		See _createRenderWindow for details about each member.		
-		@param
-		createdWindows This array will hold the created render windows.
-		@returns
-		true on success.		
-		*/
-		virtual bool _createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-			RenderWindowList& createdWindows);
-
+		RenderWindow* createRenderWindow(const String &name, unsigned int width, unsigned int height, 
+			bool fullScreen, const NameValuePairList *miscParams = 0);
 		
 		
 		/**	Create a MultiRenderTarget, which is a render target that renders to multiple RenderTextures
 		/**	Create a MultiRenderTarget, which is a render target that renders to multiple RenderTextures
 		at once. Surfaces can be bound and unbound at will.
 		at once. Surfaces can be bound and unbound at will.
@@ -613,11 +584,11 @@ namespace CamelotEngine
 		rendering operations. This viewport is aware of it's own
 		rendering operations. This viewport is aware of it's own
 		camera and render target. Must be implemented by subclass.
 		camera and render target. Must be implemented by subclass.
 
 
-		@param target Pointer to the appropriate viewport.
+		@param target Viewport to render to.
 		*/
 		*/
-		virtual void setViewport(Viewport *vp) = 0;
+		virtual void setViewport(const Viewport& vp) = 0;
 		/** Get the current active viewport for rendering. */
 		/** Get the current active viewport for rendering. */
-		virtual Viewport* getViewport(void);
+		virtual Viewport getViewport(void);
 
 
 		/** Sets the culling mode for the render system based on the 'vertex winding'.
 		/** Sets the culling mode for the render system based on the 'vertex winding'.
 		A typical way for the rendering engine to cull triangles is based on the
 		A typical way for the rendering engine to cull triangles is based on the
@@ -833,7 +804,7 @@ namespace CamelotEngine
 		@remarks Only one GpuProgram of each type can be bound at once, binding another
 		@remarks Only one GpuProgram of each type can be bound at once, binding another
 		one will simply replace the existing one.
 		one will simply replace the existing one.
 		*/
 		*/
-		virtual void bindGpuProgram(GpuProgram* prg);
+		virtual void bindGpuProgram(GpuProgramRef prg);
 
 
 		/** Bind Gpu program parameters.
 		/** Bind Gpu program parameters.
 		@param gptype The type of program to bind the parameters to
 		@param gptype The type of program to bind the parameters to
@@ -971,6 +942,14 @@ namespace CamelotEngine
 		@see Root::getDisplayMonitorCount
 		@see Root::getDisplayMonitorCount
 		*/
 		*/
 		virtual unsigned int getDisplayMonitorCount() const = 0;
 		virtual unsigned int getDisplayMonitorCount() const = 0;
+		/************************************************************************/
+		/* 							INTERNAL CALLBACKS                     		*/
+		/************************************************************************/
+	protected:
+		virtual void startUp_internal(AsyncOp& asyncOp);
+
+		virtual void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
+			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp) = 0;
 	protected:
 	protected:
 		/** The render targets. */
 		/** The render targets. */
 		RenderTargetMap mRenderTargets;
 		RenderTargetMap mRenderTargets;
@@ -984,7 +963,7 @@ namespace CamelotEngine
 		GpuProgramParametersSharedPtr mActiveFragmentGpuProgramParameters;
 		GpuProgramParametersSharedPtr mActiveFragmentGpuProgramParameters;
 
 
 		// Active viewport (dest for future rendering operations)
 		// Active viewport (dest for future rendering operations)
-		Viewport* mActiveViewport;
+		Viewport mActiveViewport;
 
 
 		CullingMode mCullingMode;
 		CullingMode mCullingMode;
 
 
@@ -1038,21 +1017,22 @@ namespace CamelotEngine
 		};
 		};
 
 
 		RenderWorkerFunc* mRenderThreadFunc;
 		RenderWorkerFunc* mRenderThreadFunc;
-		bool mUsingSeparateRenderThread;
 		bool mRenderThreadShutdown;
 		bool mRenderThreadShutdown;
 
 
 		CM_THREAD_ID_TYPE mRenderThreadId;
 		CM_THREAD_ID_TYPE mRenderThreadId;
-		CM_THREAD_SYNCHRONISER(mDeferredRSInitCondition)
-		CM_MUTEX(mDeferredRSInitMutex)
-		CM_THREAD_SYNCHRONISER(mDeferredRSReadyCondition)
-		CM_MUTEX(mDeferredRSMutex)
-		CM_MUTEX(mDeferredRSCallbackMutex)
+		CM_THREAD_SYNCHRONISER(mRSContextInitCondition)
+		CM_MUTEX(mRSContextInitMutex)
+		CM_THREAD_SYNCHRONISER(mRSContextReadyCondition)
+		CM_MUTEX(mRSContextMutex)
+		CM_MUTEX(mRSRenderCallbackMutex)
+		CM_MUTEX(mResourceContextMutex)
 
 
 #if CM_THREAD_SUPPORT
 #if CM_THREAD_SUPPORT
 		CM_THREAD_TYPE* mRenderThread;
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 #endif
 
 
-		vector<DeferredRenderSystemPtr>::type mDeferredRenderSystems;
+		RenderSystemContextPtr mResourceContext;
+		vector<RenderSystemContextPtr>::type mRenderSystemContexts;
 		boost::signal<void()> PreRenderThreadUpdateCallback;
 		boost::signal<void()> PreRenderThreadUpdateCallback;
 		boost::signal<void()> PostRenderThreadUpdateCallback;
 		boost::signal<void()> PostRenderThreadUpdateCallback;
 
 
@@ -1077,6 +1057,16 @@ namespace CamelotEngine
 		 */
 		 */
 		void throwIfInvalidThread();
 		void throwIfInvalidThread();
 
 
+		/**
+		 * @brief	Submits the specified context to the GPU. Normally this happens automatically
+		 * 			at the end of each frame for all contexts, but in some cases you might want to do it
+		 * 			manually via this method.
+		 *
+		 * @param	context			  	The context to submit.
+		 * @param	blockUntilComplete	If true, the calling thread will block until all commands are submitted.
+		 */
+		void submitToGpu(RenderSystemContextPtr context, bool blockUntilComplete);
+
 	public:
 	public:
 		/**
 		/**
 		 * @brief	Returns the id of the render thread. If a separate render thread
 		 * @brief	Returns the id of the render thread. If a separate render thread
@@ -1086,12 +1076,12 @@ namespace CamelotEngine
 		CM_THREAD_ID_TYPE getRenderThreadId() const { return mRenderThreadId; }
 		CM_THREAD_ID_TYPE getRenderThreadId() const { return mRenderThreadId; }
 
 
 		/**
 		/**
-		 * @brief	Creates a new deferred render system that you can use for rendering on 
+		 * @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
 		 * 			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 context.
 		 */
 		 */
-		DeferredRenderSystemPtr createDeferredRenderSystem();
+		RenderSystemContextPtr createRenderSystemContext();
 
 
 		/**
 		/**
 		 * @brief	Callback that is called from the render thread before it starts processing
 		 * @brief	Callback that is called from the render thread before it starts processing

+ 92 - 0
CamelotRenderer/Include/CmRenderSystemContext.h

@@ -0,0 +1,92 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmAsyncOp.h"
+#include "boost/function.hpp"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Contains context specific information for a render system.
+	 * 			Usually each thread will have its own RenderSystemContext, 
+	 * 			but you are allowed to have multiple contexts per thread.
+	 * 			Contexts can't be shared between threads though.
+	 */
+	class RenderSystemContext
+	{
+	private:
+		struct RenderSystemCommand
+		{
+			RenderSystemCommand(boost::function<void(AsyncOp&)> _callback)
+				:callback(_callback)
+			{ }
+
+			boost::function<void(AsyncOp&)> callback;
+			AsyncOp asyncOp;
+		};
+
+		/************************************************************************/
+		/* 					CALLABLE ONLY FROM RENDERSYSTEM                     */
+		/************************************************************************/
+		friend class RenderSystem;
+
+		// Actively being filled up
+		vector<RenderSystemCommand>::type* mCommands;
+
+		// Finalized and ready for rendering
+		vector<RenderSystemCommand>::type* mReadyCommands;
+
+		bool mIsShutdown;
+		bool mIsExecuting;
+
+		CM_THREAD_ID_TYPE mMyThreadId;
+		CM_MUTEX(mCommandBufferMutex)
+		CM_THREAD_SYNCHRONISER(mContextPlaybackDoneCondition)
+
+		RenderSystemContext(CM_THREAD_ID_TYPE threadId);
+
+		/**
+		 * @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.
+		 * 			This is used to signal that the command is completed, and also for storing the return
+		 * 			value.
+		 * 			
+		 * @note	Callback method also needs to call AsyncOp::markAsResolved once it is done
+		 * 			processing. (If it doesn't it will still be called automatically, but the return
+		 * 			value will default to nullptr)
+		 *
+		 * @return	Async operation object you can continuously check until the command completes.
+		 * 			After it completes AsyncOp::isResolved will return true and return data will be valid
+		 * 			(if the callback provided any).
+		 */
+		AsyncOp queueCommand(boost::function<void(AsyncOp&)> commandCallback);
+
+		/**
+		 * @brief	Plays all queued commands. Should only be called from the render thread,
+		 * 			and is normally called by the RenderSystem internally.
+		 */
+		void playbackCommands();
+
+		/**
+		 * @brief	Query if this object has any commands ready for rendering.
+		 */
+		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();
+
+		/**
+		 * @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. 
+		 */
+		void blockUntilExecuted();
+	};
+}

+ 1 - 1
CamelotRenderer/Include/CmResourceRef.h

@@ -84,7 +84,7 @@ namespace CamelotEngine
 			:ResourceRefBase()
 			:ResourceRefBase()
 		{	}
 		{	}
 
 
-		ResourceRef(T* ptr)
+		explicit ResourceRef(T* ptr)
 			:ResourceRefBase()
 			:ResourceRefBase()
 		{
 		{
 			init(ptr);
 			init(ptr);

+ 10 - 13
CamelotRenderer/Include/CmViewport.h

@@ -55,6 +55,7 @@ namespace CamelotEngine {
 	class CM_EXPORT Viewport
 	class CM_EXPORT Viewport
     {
     {
     public:       
     public:       
+		Viewport();
         /** The usual constructor.
         /** The usual constructor.
             @param
             @param
                 cam Pointer to a camera to be the source for the image.
                 cam Pointer to a camera to be the source for the image.
@@ -87,19 +88,6 @@ namespace CamelotEngine {
         */
         */
         virtual ~Viewport();
         virtual ~Viewport();
 
 
-        /** Notifies the viewport of a possible change in dimensions.
-            @remarks
-                Used by the target to update the viewport's dimensions
-                (usually the result of a change in target size).
-            @note
-                Internal use by Ogre only.
-        */
-        void _updateDimensions(void);
-
-        /** Instructs the viewport to updates its contents.
-        */
-        virtual void update(void);
-		
 		/** Instructs the viewport to clear itself, without performing an update.
 		/** Instructs the viewport to clear itself, without performing an update.
 		 @remarks
 		 @remarks
 			You would not normally call this method when updating the viewport, 
 			You would not normally call this method when updating the viewport, 
@@ -220,6 +208,15 @@ namespace CamelotEngine {
         Color mBackColour;
         Color mBackColour;
         bool mClearEveryFrame;
         bool mClearEveryFrame;
 		unsigned int mClearBuffers;
 		unsigned int mClearBuffers;
+
+		/** Notifies the viewport of a possible change in dimensions.
+            @remarks
+                Used by the target to update the viewport's dimensions
+                (usually the result of a change in target size).
+            @note
+                Internal use by engine only.
+        */
+        void updateDimensions(void);
     };
     };
 	/** @} */
 	/** @} */
 	/** @} */
 	/** @} */

+ 6 - 3
CamelotRenderer/Source/CmApplication.cpp

@@ -49,10 +49,11 @@ namespace CamelotEngine
 		RendererManager::setActive("ForwardRenderer");
 		RendererManager::setActive("ForwardRenderer");
 
 
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
-		renderSystem->startUp(true, false, "Camelot Renderer");
-		renderSystem->addPreRenderThreadUpdateCallback(boost::bind(&Application::updateResourcesCallback, this));
+		renderSystem->startUp();
+
+		//mPrimaryDeferredRenderSystem = renderSystem->createRenderSystemContext();
+		mPrimaryDeferredRenderSystem = nullptr;
 
 
-		mPrimaryDeferredRenderSystem = renderSystem->createDeferredRenderSystem();
 		mPrimaryRenderWindow = renderSystem->createRenderWindow("Camelot Renderer", 1280, 720, false);
 		mPrimaryRenderWindow = renderSystem->createRenderWindow("Camelot Renderer", 1280, 720, false);
 
 
 		SceneManager::startUp(new SceneManager());
 		SceneManager::startUp(new SceneManager());
@@ -63,6 +64,8 @@ namespace CamelotEngine
 		loadPlugin("CamelotFBXImporter"); // TODO - Load this automatically somehow
 		loadPlugin("CamelotFBXImporter"); // TODO - Load this automatically somehow
 
 
 		loadPlugin("CamelotOISInput"); // TODO - Load this automatically somehow
 		loadPlugin("CamelotOISInput"); // TODO - Load this automatically somehow
+
+		renderSystem->addPreRenderThreadUpdateCallback(boost::bind(&Application::updateResourcesCallback, this));
 	}
 	}
 
 
 	void Application::runMainLoop()
 	void Application::runMainLoop()

+ 31 - 5
CamelotRenderer/Source/CmDeferredGpuCommands.cpp

@@ -6,6 +6,14 @@ namespace CamelotEngine
 	DeferredGpuCommand::DeferredGpuCommand()
 	DeferredGpuCommand::DeferredGpuCommand()
 	{ }
 	{ }
 
 
+	DfrdRSStartUpCommand::DfrdRSStartUpCommand()
+	{ }
+
+	void DfrdRSStartUpCommand::submitCommand(RenderSystem* rs)
+	{
+		//rs->startUp_internal();
+	}
+
 	DfrdRenderGpuCommand::DfrdRenderGpuCommand(RenderOperation& _renderOp)
 	DfrdRenderGpuCommand::DfrdRenderGpuCommand(RenderOperation& _renderOp)
 		:renderOp(_renderOp)
 		:renderOp(_renderOp)
 	{ }
 	{ }
@@ -15,13 +23,22 @@ namespace CamelotEngine
 		rs->render(renderOp);
 		rs->render(renderOp);
 	}
 	}
 
 
-	DfrdBindGpuProgramCommand::DfrdBindGpuProgramCommand(GpuProgramPtr _gpuProgram)
+	DfrdBindGpuProgramCommand::DfrdBindGpuProgramCommand(GpuProgramRef _gpuProgram)
 		:gpuProgram(_gpuProgram)
 		:gpuProgram(_gpuProgram)
 	{ }
 	{ }
 
 
 	void DfrdBindGpuProgramCommand::submitCommand(RenderSystem* rs)
 	void DfrdBindGpuProgramCommand::submitCommand(RenderSystem* rs)
 	{
 	{
-		rs->bindGpuProgram(gpuProgram.get());
+		rs->bindGpuProgram(gpuProgram);
+	}
+
+	DfrdUnbindGpuProgramCommand::DfrdUnbindGpuProgramCommand(GpuProgramType _type)
+		:type(_type)
+	{ }
+
+	void DfrdUnbindGpuProgramCommand::submitCommand(RenderSystem* rs)
+	{
+		rs->unbindGpuProgram(type);
 	}
 	}
 
 
 	DfrdBindGpuParamsCommand::DfrdBindGpuParamsCommand(GpuProgramType _type, GpuProgramParametersPtr& _progParams)
 	DfrdBindGpuParamsCommand::DfrdBindGpuParamsCommand(GpuProgramType _type, GpuProgramParametersPtr& _progParams)
@@ -225,13 +242,13 @@ namespace CamelotEngine
 		rs->setAlphaRejectSettings(func, value, alphaToCoverage);
 		rs->setAlphaRejectSettings(func, value, alphaToCoverage);
 	}
 	}
 
 
-// TODO
-	DfrdViewportCommand::DfrdViewportCommand()
+	DfrdViewportCommand::DfrdViewportCommand(const Viewport& _vp)
+		:vp(_vp)
 	{ }
 	{ }
 
 
 	void DfrdViewportCommand::submitCommand(RenderSystem* rs)
 	void DfrdViewportCommand::submitCommand(RenderSystem* rs)
 	{
 	{
-
+		rs->setViewport(vp);
 	}
 	}
 
 
 	DfrdCullingCommand::DfrdCullingCommand(CullingMode _mode)
 	DfrdCullingCommand::DfrdCullingCommand(CullingMode _mode)
@@ -341,4 +358,13 @@ namespace CamelotEngine
 	{
 	{
 		rs->clearFrameBuffer(buffers, color, depth, stencil);
 		rs->clearFrameBuffer(buffers, color, depth, stencil);
 	}
 	}
+
+	DfrdSwapAllRenderTargetBuffersCommand::DfrdSwapAllRenderTargetBuffersCommand(bool _waitForVsync)
+		:waitForVsync(_waitForVsync)
+	{ }
+
+	void DfrdSwapAllRenderTargetBuffersCommand::submitCommand(RenderSystem* rs)
+	{
+		rs->swapAllRenderTargetBuffers(waitForVsync);
+	}
 }
 }

+ 19 - 3
CamelotRenderer/Source/CmDeferredRenderSystem.cpp

@@ -44,7 +44,7 @@ namespace CamelotEngine
 		mActiveRenderCommandBuffer->push_back(newCommand);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 	}
 	}
 
 
-	void DeferredRenderSystem::bindGpuProgram(GpuProgramPtr prg)
+	void DeferredRenderSystem::bindGpuProgram(GpuProgramRef prg)
 	{
 	{
 		throwIfInvalidThread();
 		throwIfInvalidThread();
 
 
@@ -52,6 +52,14 @@ namespace CamelotEngine
 		mActiveRenderCommandBuffer->push_back(newCommand);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 	}
 	}
 
 
+	void DeferredRenderSystem::unbindGpuProgram(GpuProgramType gptype)
+	{
+		throwIfInvalidThread();
+
+		DfrdUnbindGpuProgramCommand* newCommand = new DfrdUnbindGpuProgramCommand(gptype);
+		mActiveRenderCommandBuffer->push_back(newCommand);
+	}
+
 	void DeferredRenderSystem::bindGpuProgramParameters(GpuProgramType gptype, GpuProgramParametersSharedPtr params)
 	void DeferredRenderSystem::bindGpuProgramParameters(GpuProgramType gptype, GpuProgramParametersSharedPtr params)
 	{
 	{
 		throwIfInvalidThread();
 		throwIfInvalidThread();
@@ -239,11 +247,11 @@ namespace CamelotEngine
 		mActiveRenderCommandBuffer->push_back(newCommand);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 	}
 	}
 		
 		
-	void DeferredRenderSystem::setViewport(Viewport *vp)
+	void DeferredRenderSystem::setViewport(const Viewport& vp)
 	{
 	{
 		throwIfInvalidThread();
 		throwIfInvalidThread();
 
 
-		DfrdViewportCommand* newCommand = new DfrdViewportCommand();
+		DfrdViewportCommand* newCommand = new DfrdViewportCommand(vp);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 	}
 	}
 		
 		
@@ -344,6 +352,14 @@ namespace CamelotEngine
 		mActiveRenderCommandBuffer->push_back(newCommand);
 		mActiveRenderCommandBuffer->push_back(newCommand);
 	}
 	}
 
 
+	void DeferredRenderSystem::swapAllRenderTargetBuffers(bool waitForVsync)
+	{
+		throwIfInvalidThread();
+
+		DfrdSwapAllRenderTargetBuffersCommand* newCommand = new DfrdSwapAllRenderTargetBuffersCommand(waitForVsync);
+		mActiveRenderCommandBuffer->push_back(newCommand);
+	}
+
 	void DeferredRenderSystem::submitToGpu()
 	void DeferredRenderSystem::submitToGpu()
 	{
 	{
 		{
 		{

+ 88 - 120
CamelotRenderer/Source/CmRenderSystem.cpp

@@ -40,6 +40,7 @@ THE SOFTWARE.
 #include "CmHardwarePixelBuffer.h"
 #include "CmHardwarePixelBuffer.h"
 #include "CmHardwareOcclusionQuery.h"
 #include "CmHardwareOcclusionQuery.h"
 #include "CmDeferredRenderSystem.h"
 #include "CmDeferredRenderSystem.h"
+#include "CmRenderSystemContext.h"
 #include "boost/bind.hpp"
 #include "boost/bind.hpp"
 
 
 namespace CamelotEngine {
 namespace CamelotEngine {
@@ -49,7 +50,6 @@ namespace CamelotEngine {
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
     RenderSystem::RenderSystem()
     RenderSystem::RenderSystem()
         : mActiveRenderTarget(0)
         : mActiveRenderTarget(0)
-        , mActiveViewport(0)
         // This means CULL clockwise vertices, i.e. front of poly is counter-clockwise
         // 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
         // This makes it the same as OpenGL and other right-handed systems
         , mCullingMode(CULL_CLOCKWISE)
         , mCullingMode(CULL_CLOCKWISE)
@@ -64,7 +64,6 @@ namespace CamelotEngine {
 		, mRealCapabilities(0)
 		, mRealCapabilities(0)
 		, mCurrentCapabilities(0)
 		, mCurrentCapabilities(0)
 		, mUseCustomCapabilities(false)
 		, mUseCustomCapabilities(false)
-		, mUsingSeparateRenderThread(false)
 		, mRenderThreadFunc(nullptr)
 		, mRenderThreadFunc(nullptr)
 		, mRenderThreadShutdown(false)
 		, mRenderThreadShutdown(false)
     {
     {
@@ -93,94 +92,47 @@ namespace CamelotEngine {
 		}
 		}
     }
     }
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
-    RenderWindow* RenderSystem::startUp(bool runOnSeparateThread, bool autoCreateWindow, const String& windowTitle)
+    void RenderSystem::startUp()
     {
     {
-        // Subclasses should take it from here
-        // They should ALL call this superclass method from
-        //   their own startUp() implementations.
-
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
+		mResourceContext = 	createRenderSystemContext();
 
 
-        mVertexProgramBound = false;
-		mGeometryProgramBound = false;
-        mFragmentProgramBound = false;
-
-		if(runOnSeparateThread)
-			initRenderThread();
-
-        return 0;
-    }
+		initRenderThread(); // TODO - Move render thread to the outside of the RS
 
 
-	//---------------------------------------------------------------------------------------------
-	void RenderSystem::useCustomRenderSystemCapabilities(RenderSystemCapabilities* capabilities)
-	{
-    if (mRealCapabilities != 0)
-    {
-		CM_EXCEPT(InternalErrorException, 
-          "Custom render capabilities must be set before the RenderSystem is initialised.");
+		{
+			CM_LOCK_MUTEX(mResourceContextMutex)
+			mResourceContext->queueCommand(boost::bind(&RenderSystem::startUp_internal, this, _1));
+		}
     }
     }
-
-		mCurrentCapabilities = capabilities;
-		mUseCustomCapabilities = true;
-	}
-
 	//---------------------------------------------------------------------------------------------
 	//---------------------------------------------------------------------------------------------
-	bool RenderSystem::_createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 
-		RenderWindowList& createdWindows)
+	RenderWindow* RenderSystem::createRenderWindow(const String &name, unsigned int width, unsigned int height, 
+		bool fullScreen, const NameValuePairList *miscParams)
 	{
 	{
-		unsigned int fullscreenWindowsCount = 0;
-
-		// Grab some information and avoid duplicate render windows.
-		for (unsigned int nWindow=0; nWindow < renderWindowDescriptions.size(); ++nWindow)
+		AsyncOp op;
 		{
 		{
-			const RenderWindowDescription* curDesc = &renderWindowDescriptions[nWindow];
-
-			// Count full screen windows.
-			if (curDesc->useFullScreen)			
-				fullscreenWindowsCount++;	
+			CM_LOCK_MUTEX(mResourceContextMutex)
 
 
-			bool renderWindowFound = false;
-
-			if (mRenderTargets.find(curDesc->name) != mRenderTargets.end())
-				renderWindowFound = true;
+			if(miscParams != nullptr)
+				op = mResourceContext->queueCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, *miscParams, _1));
 			else
 			else
-			{
-				for (unsigned int nSecWindow = nWindow + 1 ; nSecWindow < renderWindowDescriptions.size(); ++nSecWindow)
-				{
-					if (curDesc->name == renderWindowDescriptions[nSecWindow].name)
-					{
-						renderWindowFound = true;
-						break;
-					}					
-				}
-			}
-
-			// Make sure we don't already have a render target of the 
-			// same name as the one supplied
-			if(renderWindowFound)
-			{
-				String msg;
-
-				msg = "A render target of the same name '" + String(curDesc->name) + "' already "
-					"exists.  You cannot create a new window with this name.";
-				CM_EXCEPT(InternalErrorException, msg);
-			}
+				op = mResourceContext->queueCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, NameValuePairList(), _1));
 		}
 		}
-		
-		// Case we have to create some full screen rendering windows.
-		if (fullscreenWindowsCount > 0)
+
+		submitToGpu(mResourceContext, true);
+		return op.getReturnValue<RenderWindow*>();
+	}
+	//---------------------------------------------------------------------------------------------
+	void RenderSystem::useCustomRenderSystemCapabilities(RenderSystemCapabilities* capabilities)
+	{
+		if (mRealCapabilities != 0)
 		{
 		{
-			// Can not mix full screen and windowed rendering windows.
-			if (fullscreenWindowsCount != renderWindowDescriptions.size())
-			{
-				CM_EXCEPT(InvalidParametersException, 
-					"Can not create mix of full screen and windowed rendering windows");
-			}					
+			CM_EXCEPT(InternalErrorException, 
+				"Custom render capabilities must be set before the RenderSystem is initialised.");
 		}
 		}
 
 
-		return true;
+		mCurrentCapabilities = capabilities;
+		mUseCustomCapabilities = true;
 	}
 	}
-
     //---------------------------------------------------------------------------------------------
     //---------------------------------------------------------------------------------------------
     void RenderSystem::destroyRenderWindow(const String& name)
     void RenderSystem::destroyRenderWindow(const String& name)
     {
     {
@@ -251,7 +203,7 @@ namespace CamelotEngine {
         return ret;
         return ret;
     }
     }
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
-    Viewport* RenderSystem::getViewport(void)
+    Viewport RenderSystem::getViewport(void)
     {
     {
         return mActiveViewport;
         return mActiveViewport;
     }
     }
@@ -369,8 +321,7 @@ namespace CamelotEngine {
 
 
 		mPrioritisedRenderTargets.clear();
 		mPrioritisedRenderTargets.clear();
 
 
-		if(mUsingSeparateRenderThread)
-			shutdownRenderThread();
+		shutdownRenderThread();
     }
     }
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
     void RenderSystem::beginGeometryCount(void)
     void RenderSystem::beginGeometryCount(void)
@@ -476,9 +427,9 @@ namespace CamelotEngine {
 		}
 		}
 	}
 	}
 	//-----------------------------------------------------------------------
 	//-----------------------------------------------------------------------
-	void RenderSystem::bindGpuProgram(GpuProgram* prg)
+	void RenderSystem::bindGpuProgram(GpuProgramRef prg)
 	{
 	{
-	    switch(prg->getType())
+	    switch(prg->_getBindingDelegate()->getType())
 	    {
 	    {
         case GPT_VERTEX_PROGRAM:
         case GPT_VERTEX_PROGRAM:
 			// mark clip planes dirty if changed (programmable can change space)
 			// mark clip planes dirty if changed (programmable can change space)
@@ -538,10 +489,9 @@ namespace CamelotEngine {
 		CM_THREAD_CREATE(t, *mRenderThreadFunc);
 		CM_THREAD_CREATE(t, *mRenderThreadFunc);
 		mRenderThread = t;
 		mRenderThread = t;
 
 
-		CM_LOCK_MUTEX_NAMED(mDeferredRSInitMutex, lock)
-		CM_THREAD_WAIT(mDeferredRSInitCondition, mDeferredRSInitMutex, lock)
+		CM_LOCK_MUTEX_NAMED(mRSContextInitMutex, lock)
+		CM_THREAD_WAIT(mRSContextInitCondition, mRSContextInitMutex, lock)
 
 
-		// TODO - Block here until I am sure render thread is running and initialized
 #else
 #else
 		CM_EXCEPT(InternalErrorException, "Attempting to start a render thread but Camelot isn't compiled with thread support.");
 		CM_EXCEPT(InternalErrorException, "Attempting to start a render thread but Camelot isn't compiled with thread support.");
 #endif
 #endif
@@ -550,30 +500,31 @@ namespace CamelotEngine {
 	void RenderSystem::runRenderThread()
 	void RenderSystem::runRenderThread()
 	{
 	{
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
-		mUsingSeparateRenderThread = true;
 
 
-		CM_THREAD_NOTIFY_ALL(mDeferredRSInitCondition)
+		CM_THREAD_NOTIFY_ALL(mRSContextInitCondition)
 
 
 		while(true)
 		while(true)
 		{
 		{
 			if(mRenderThreadShutdown)
 			if(mRenderThreadShutdown)
 				return;
 				return;
 
 
-			vector<DeferredRenderSystemPtr>::type deferredRenderSystemsCopy;
+			vector<RenderSystemContextPtr>::type renderSystemContextsCopy;
 			{
 			{
-				CM_LOCK_MUTEX(mDeferredRSMutex);
+				CM_LOCK_MUTEX(mRSContextMutex);
 
 
-				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
-					deferredRenderSystemsCopy.push_back(*iter);
+				for(auto iter = mRenderSystemContexts.begin(); iter != mRenderSystemContexts.end(); ++iter)
+				{
+					renderSystemContextsCopy.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(mRSContextMutex, lock)
 
 
 				bool anyCommandsReady = false;
 				bool anyCommandsReady = false;
-				for(auto iter = deferredRenderSystemsCopy.begin(); iter != deferredRenderSystemsCopy.end(); ++iter)
+				for(auto iter = renderSystemContextsCopy.begin(); iter != renderSystemContextsCopy.end(); ++iter)
 				{
 				{
 					if((*iter)->hasReadyCommands())
 					if((*iter)->hasReadyCommands())
 					{
 					{
@@ -583,24 +534,24 @@ namespace CamelotEngine {
 				}
 				}
 
 
 				if(!anyCommandsReady)
 				if(!anyCommandsReady)
-					CM_THREAD_WAIT(mDeferredRSReadyCondition, mDeferredRSMutex, lock)
+					CM_THREAD_WAIT(mRSContextReadyCondition, mRSContextMutex, lock)
 			}
 			}
 
 
 			{
 			{
-				CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+				CM_LOCK_MUTEX(mRSRenderCallbackMutex)
 
 
 				if(!PreRenderThreadUpdateCallback.empty())
 				if(!PreRenderThreadUpdateCallback.empty())
 					PreRenderThreadUpdateCallback();
 					PreRenderThreadUpdateCallback();
 			}
 			}
 
 
 			// Play commands
 			// Play commands
-			for(auto iter = deferredRenderSystemsCopy.begin(); iter != deferredRenderSystemsCopy.end(); ++iter)
+			for(auto iter = renderSystemContextsCopy.begin(); iter != renderSystemContextsCopy.end(); ++iter)
 			{
 			{
 				(*iter)->playbackCommands();
 				(*iter)->playbackCommands();
 			}
 			}
 
 
 			{
 			{
-				CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+				CM_LOCK_MUTEX(mRSRenderCallbackMutex)
 
 
 				if(!PostRenderThreadUpdateCallback.empty())
 				if(!PostRenderThreadUpdateCallback.empty())
 					PostRenderThreadUpdateCallback();
 					PostRenderThreadUpdateCallback();
@@ -614,66 +565,70 @@ namespace CamelotEngine {
 		mRenderThreadShutdown = true;
 		mRenderThreadShutdown = true;
 
 
 		// Wake all threads. They will quit after they see the shutdown flag
 		// Wake all threads. They will quit after they see the shutdown flag
-		CM_THREAD_NOTIFY_ALL(mDeferredRSReadyCondition)
+		CM_THREAD_NOTIFY_ALL(mRSContextReadyCondition)
 
 
 		mRenderThread->join();
 		mRenderThread->join();
 		CM_THREAD_DESTROY(mRenderThread);
 		CM_THREAD_DESTROY(mRenderThread);
 
 
 		mRenderThread = nullptr;
 		mRenderThread = nullptr;
-		mUsingSeparateRenderThread = false;
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
 		mRenderThreadId = CM_THREAD_CURRENT_ID;
-		mDeferredRenderSystems.clear();
+		mRenderSystemContexts.clear();
 	}
 	}
 
 
-	DeferredRenderSystemPtr RenderSystem::createDeferredRenderSystem()
+	RenderSystemContextPtr RenderSystem::createRenderSystemContext()
 	{
 	{
-		if(!mUsingSeparateRenderThread)
-		{
-			CM_EXCEPT(InternalErrorException, "Cannot create deferred rendering system because separate render thread is not active.");
-		}
-
-		DeferredRenderSystemPtr newDeferredRS = DeferredRenderSystemPtr(
-			new DeferredRenderSystem(CM_THREAD_CURRENT_ID)
+		RenderSystemContextPtr newContext = RenderSystemContextPtr(
+			new RenderSystemContext(CM_THREAD_CURRENT_ID)
 			);
 			);
 
 
 		{
 		{
-			CM_LOCK_MUTEX(mDeferredRSMutex);
-			mDeferredRenderSystems.push_back(newDeferredRS);
+			CM_LOCK_MUTEX(mRSContextMutex);
+			mRenderSystemContexts.push_back(newContext);
 		}
 		}
 
 
-		return newDeferredRS;
+		return newContext;
 	}
 	}
 
 
 	void RenderSystem::addPreRenderThreadUpdateCallback(boost::function<void()> callback)
 	void RenderSystem::addPreRenderThreadUpdateCallback(boost::function<void()> callback)
 	{
 	{
-		CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+		CM_LOCK_MUTEX(mRSRenderCallbackMutex)
 
 
 		PreRenderThreadUpdateCallback.connect(callback);
 		PreRenderThreadUpdateCallback.connect(callback);
 	}
 	}
 
 
 	void RenderSystem::addPostRenderThreadUpdateCallback(boost::function<void()> callback)
 	void RenderSystem::addPostRenderThreadUpdateCallback(boost::function<void()> callback)
 	{
 	{
-		CM_LOCK_MUTEX(mDeferredRSCallbackMutex)
+		CM_LOCK_MUTEX(mRSRenderCallbackMutex)
 
 
 		PostRenderThreadUpdateCallback.connect(callback);
 		PostRenderThreadUpdateCallback.connect(callback);
 	}
 	}
 
 
+	void RenderSystem::submitToGpu(RenderSystemContextPtr context, bool blockUntilComplete)
+	{
+		{
+			CM_LOCK_MUTEX(mRSContextMutex);
+
+			context->submitToGpu();
+		}
+
+		CM_THREAD_NOTIFY_ALL(mRSContextReadyCondition);
+
+		if(blockUntilComplete)
+			context->blockUntilExecuted();
+	}
+
 	void RenderSystem::update()
 	void RenderSystem::update()
 	{
 	{
-		if(mUsingSeparateRenderThread)
 		{
 		{
-			{
-				CM_LOCK_MUTEX(mDeferredRSMutex);
+			CM_LOCK_MUTEX(mRSContextMutex);
 
 
-				for(auto iter = mDeferredRenderSystems.begin(); iter != mDeferredRenderSystems.end(); ++iter)
-				{
-					(*iter)->submitToGpu();
-				}
+			for(auto iter = mRenderSystemContexts.begin(); iter != mRenderSystemContexts.end(); ++iter)
+			{
+				(*iter)->submitToGpu();
 			}
 			}
-
-			CM_THREAD_NOTIFY_ALL(mDeferredRSReadyCondition)
 		}
 		}
 
 
+		CM_THREAD_NOTIFY_ALL(mRSContextReadyCondition)
 	}
 	}
 
 
 	void RenderSystem::throwIfInvalidThread()
 	void RenderSystem::throwIfInvalidThread()
@@ -682,6 +637,19 @@ namespace CamelotEngine {
 			CM_EXCEPT(InternalErrorException, "Calling the render system from a non-render thread!");
 			CM_EXCEPT(InternalErrorException, "Calling the render system from a non-render thread!");
 	}
 	}
 
 
+	/************************************************************************/
+	/* 							INTERNAL CALLBACKS                     		*/
+	/************************************************************************/
+
+	void RenderSystem::startUp_internal(AsyncOp& asyncOp)
+	{
+		mVertexProgramBound = false;
+		mGeometryProgramBound = false;
+		mFragmentProgramBound = false;
+
+		asyncOp.completeOperation();
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								THREAD WORKER                      		*/
 	/* 								THREAD WORKER                      		*/
 	/************************************************************************/
 	/************************************************************************/

+ 125 - 0
CamelotRenderer/Source/CmRenderSystemContext.cpp

@@ -0,0 +1,125 @@
+#include "CmRenderSystemContext.h"
+#include "CmException.h"
+#include "CmRenderSystemManager.h"
+#include "CmRenderSystem.h"
+#include "CmDebug.h"
+
+namespace CamelotEngine
+{
+	RenderSystemContext::RenderSystemContext(CM_THREAD_ID_TYPE threadId)
+		:mMyThreadId(threadId), mReadyCommands(nullptr), mIsExecuting(false)
+	{
+		mCommands = new vector<RenderSystemCommand>::type();
+	}
+
+	AsyncOp RenderSystemContext::queueCommand(boost::function<void(AsyncOp&)> commandCallback)
+	{
+#if CM_DEBUG_MODE
+#if CM_THREAD_SUPPORT != 0
+		if(CM_THREAD_CURRENT_ID != mMyThreadId)
+		{
+			CM_EXCEPT(InternalErrorException, "Render system context accessed from an invalid thread.");
+		}
+#endif
+#endif
+
+		RenderSystemCommand newCommand(commandCallback);
+		mCommands->push_back(newCommand);
+
+		return newCommand.asyncOp;
+	}
+
+	void RenderSystemContext::submitToGpu()
+	{
+		{
+			CM_LOCK_MUTEX(mCommandBufferMutex);
+
+			if(mReadyCommands != nullptr)
+			{
+				delete mReadyCommands;
+				mReadyCommands = nullptr;
+			}
+
+			mReadyCommands = mCommands;
+			mCommands = new vector<RenderSystemCommand>::type();
+		}
+	}
+
+	void RenderSystemContext::playbackCommands()
+	{
+#if CM_DEBUG_MODE
+		RenderSystem* rs = RenderSystemManager::getActive();
+
+		if(rs->getRenderThreadId() != CM_THREAD_CURRENT_ID)
+			CM_EXCEPT(InternalErrorException, "This method should only be called from the render thread.");
+#endif
+
+		vector<RenderSystemCommand>::type* currentCommands = nullptr;
+		{
+			CM_LOCK_MUTEX(mCommandBufferMutex)
+
+			currentCommands = mReadyCommands;
+			mReadyCommands = nullptr;
+			mIsExecuting = true;
+		}
+
+		if(currentCommands == nullptr)
+		{
+			{
+				CM_LOCK_MUTEX(mCommandBufferMutex);
+				mIsExecuting = false;
+			}
+
+			CM_THREAD_NOTIFY_ALL(mContextPlaybackDoneCondition)
+			return;
+		}
+
+		for(auto iter = currentCommands->begin(); iter != currentCommands->end(); ++iter)
+		{
+			(*iter).callback((*iter).asyncOp);
+
+			if(!(*iter).asyncOp.hasCompleted())
+			{
+				LOGDBG("Async operation wasn't resolved properly. Resolving automatically to nullptr.");
+				(*iter).asyncOp.completeOperation(nullptr);
+			}
+		}
+
+		delete currentCommands;
+
+		{
+			CM_LOCK_MUTEX(mCommandBufferMutex);
+			mIsExecuting = false;
+		}
+
+		CM_THREAD_NOTIFY_ALL(mContextPlaybackDoneCondition)
+	}
+
+	bool RenderSystemContext::hasReadyCommands()
+	{
+		CM_LOCK_MUTEX(mCommandBufferMutex);
+
+		if(mReadyCommands != nullptr && mReadyCommands->size() > 0)
+			return true;
+
+		return false;
+	}
+
+	void RenderSystemContext::blockUntilExecuted()
+	{
+#if CM_DEBUG_MODE
+		RenderSystem* rs = RenderSystemManager::getActive();
+
+		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
+
+		{
+			CM_LOCK_MUTEX_NAMED(mCommandBufferMutex, lock);
+			while (mReadyCommands != nullptr && mReadyCommands->size() > 0 || mIsExecuting)
+			{
+				CM_THREAD_WAIT(mContextPlaybackDoneCondition, mCommandBufferMutex, lock)
+			}
+		}
+	}
+}

+ 25 - 18
CamelotRenderer/Source/CmViewport.cpp

@@ -34,6 +34,23 @@ THE SOFTWARE.
 #include "CmRenderSystemManager.h"
 #include "CmRenderSystemManager.h"
 
 
 namespace CamelotEngine {
 namespace CamelotEngine {
+
+	//---------------------------------------------------------------------
+	Viewport::Viewport()
+		:mTarget(nullptr)
+		, mRelLeft(0)
+		, mRelTop(0)
+		, mRelWidth(0)
+		, mRelHeight(0)
+		// Actual dimensions will update later
+		, mZOrder(0)
+		, mBackColour(Color::Black)
+		, mClearEveryFrame(true)
+		, mClearBuffers(FBT_COLOUR | FBT_DEPTH)
+	{
+		// Calculate actual dimensions
+		updateDimensions();
+	}
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
     Viewport::Viewport(RenderTarget* target, float left, float top, float width, float height, int ZOrder)
     Viewport::Viewport(RenderTarget* target, float left, float top, float width, float height, int ZOrder)
          :mTarget(target)
          :mTarget(target)
@@ -48,7 +65,7 @@ namespace CamelotEngine {
 		, mClearBuffers(FBT_COLOUR | FBT_DEPTH)
 		, mClearBuffers(FBT_COLOUR | FBT_DEPTH)
     {
     {
         // Calculate actual dimensions
         // Calculate actual dimensions
-        _updateDimensions();
+        updateDimensions();
     }
     }
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
     Viewport::~Viewport()
     Viewport::~Viewport()
@@ -56,7 +73,7 @@ namespace CamelotEngine {
 
 
     }
     }
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
-    void Viewport::_updateDimensions(void)
+    void Viewport::updateDimensions(void)
     {
     {
 		if(mTarget != nullptr)
 		if(mTarget != nullptr)
 		{
 		{
@@ -126,12 +143,7 @@ namespace CamelotEngine {
         mRelTop = top;
         mRelTop = top;
         mRelWidth = width;
         mRelWidth = width;
         mRelHeight = height;
         mRelHeight = height;
-        _updateDimensions();
-    }
-    //---------------------------------------------------------------------
-    void Viewport::update(void)
-    {
-
+        updateDimensions();
     }
     }
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
     void Viewport::setBackgroundColour(const Color& colour)
     void Viewport::setBackgroundColour(const Color& colour)
@@ -166,15 +178,11 @@ namespace CamelotEngine {
 		RenderSystem* rs = CamelotEngine::RenderSystemManager::getActive();
 		RenderSystem* rs = CamelotEngine::RenderSystemManager::getActive();
 		if (rs)
 		if (rs)
 		{
 		{
-			Viewport* currentvp = rs->getViewport();
-			if (currentvp && currentvp == this)
-				rs->clearFrameBuffer(buffers, col, depth, stencil);
-			else if (currentvp)
-			{
-				rs->setViewport(this);
-				rs->clearFrameBuffer(buffers, col, depth, stencil);
-				rs->setViewport(currentvp);
-			}
+			Viewport currentvp = rs->getViewport();
+
+			rs->setViewport(*this);
+			rs->clearFrameBuffer(buffers, col, depth, stencil);
+			rs->setViewport(currentvp);
 		}
 		}
 	}
 	}
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
@@ -186,5 +194,4 @@ namespace CamelotEngine {
         height = mActHeight;
         height = mActHeight;
 
 
     }
     }
-	//-----------------------------------------------------------------------
 }
 }

+ 10 - 6
CamelotRenderer/TODO.txt

@@ -16,6 +16,13 @@ High-level TODO:
 
 
 
 
 Command buffer TODO:
 Command buffer TODO:
+ Immediate:
+ - Rename ResourceRef to ResourceHandle?
+ - setVertexDeclaration/setVertexBufferBinding still need their deferred versions
+ - schedule startUp to happen on render thread
+   - do the same in OpenGL
+ - surround the thread checks with #if _DEBUG
+
 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
@@ -36,11 +43,7 @@ Essential TODO for deferred rendering:
 
 
  - Modify resource creation so it calls RenderContext and just schedules resource creation
  - Modify resource creation so it calls RenderContext and just schedules resource creation
 
 
- - (Optional) Add callbacks from render thread (e.g. pre/post render) and only allow users to create vertex buffer and similar manually from there? at least temporarily. "Direct" access from worker threads might be useful, although users should always be able to use abstractions like Mesh and similar.
-   - Reading from resources should however block the render thread and get the actual resource. Reading is slow anyway and won't be done often.
-   - Writing can be accomplished if RenderContext just returns temporary memory we can write to, and then actually writes it during playback.
-   - Both reading & writing can be accomplished if we keep all data in system memory, which GL does internally (but we can't access it), and optionally DX does too (but again, can't access it). Unless we can access it it's too much memory overhead.
-
+ - Figure out how to handle reading of resources properly
 
 
 
 
 
 
@@ -79,9 +82,10 @@ Low priority TODO:
  - Serializable callbacks can't be null otherwise compiler complains
  - Serializable callbacks can't be null otherwise compiler complains
  - Depth test is disabled by default (OpenGL renderer at least)
  - Depth test is disabled by default (OpenGL renderer at least)
  - Are resource getting properly unloaded? e.g. when shared_ptr destroys a texture is it removed from gpu?
  - Are resource getting properly unloaded? e.g. when shared_ptr destroys a texture is it removed from gpu?
+  - Make sure resources only get properly unloaded at end of every frame. This is because a lot of RenderSystem stuff holds raw ptrs
+	to resources, and it keeps them throughout the frame (especially with deferred rendering). Plus this can only be done on the render thread anyway.
  - Remove template from RTTIType and move it to IReflectable? This way i can hopefully move GetRTTITypeStatic and GetRTTIType to IReflectable so I don't
  - Remove template from RTTIType and move it to IReflectable? This way i can hopefully move GetRTTITypeStatic and GetRTTIType to IReflectable so I don't
    need to manually implement those for every method.
    need to manually implement those for every method.
- - Removed unused methods from D3D9 and GL render systems (mostly fixed function stuff)
  - Viewport needs to be updated when I call RenderTarget::setFullscreen/finishSwitchingFullscreen/updateWindowRect/windowMovedOrResized. Currently it's not
  - Viewport needs to be updated when I call RenderTarget::setFullscreen/finishSwitchingFullscreen/updateWindowRect/windowMovedOrResized. Currently it's not
  - D3D9Texture::createTextureResources is commented out at the moment. It gets called on device reset, and at that point I should reload texture resources.
  - D3D9Texture::createTextureResources is commented out at the moment. It gets called on device reset, and at that point I should reload texture resources.
   - I should probably keep all resources by DX managed. OpenGL apparently keeps a mirror of all its resources anyway.
   - I should probably keep all resources by DX managed. OpenGL apparently keeps a mirror of all its resources anyway.

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -87,6 +87,7 @@
     <ClCompile Include="Source\CmUUID.cpp" />
     <ClCompile Include="Source\CmUUID.cpp" />
     <ClCompile Include="Source\CmWorkQueue.cpp" />
     <ClCompile Include="Source\CmWorkQueue.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
+    <ClInclude Include="Include\CmAsyncOp.h" />
     <ClInclude Include="Include\CmBinarySerializer.h" />
     <ClInclude Include="Include\CmBinarySerializer.h" />
     <ClInclude Include="Include\CmBitwise.h" />
     <ClInclude Include="Include\CmBitwise.h" />
     <ClInclude Include="Include\CmBox.h" />
     <ClInclude Include="Include\CmBox.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -198,6 +198,9 @@
     <ClInclude Include="Include\CmInt2.h">
     <ClInclude Include="Include\CmInt2.h">
       <Filter>Header Files\Math</Filter>
       <Filter>Header Files\Math</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmAsyncOp.h">
+      <Filter>Header Files\Threading</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">

+ 65 - 0
CamelotUtility/Include/CmAsyncOp.h

@@ -0,0 +1,65 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "boost/any.hpp"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Asynchronous operation. Contains uninitialized data until
+	 * 			isResolved returns true.
+	 * 			
+	 * @note	You are allowed (and meant to) to copy this by value.
+	 */
+	class AsyncOp
+	{
+	private:
+		struct AsyncOpData
+		{
+			AsyncOpData()
+				:mIsCompleted(false)
+			{ }
+
+			boost::any mReturnValue;
+			bool mIsCompleted;
+		};
+
+	public:
+		AsyncOp()
+			:mData(new AsyncOpData())
+		{}
+
+		/**
+		 * @brief	True if the async operation has completed.
+		 */
+		bool hasCompleted() const { return mData->mIsCompleted; }
+
+		/**
+		 * @brief	Mark the async operation as completed.
+		 */
+		void completeOperation(boost::any returnValue) { mData->mReturnValue = returnValue; mData->mIsCompleted = true; }
+
+		/**
+		 * @brief	Mark the async operation as completed, without setting a return value;
+		 */
+		void completeOperation() { mData->mIsCompleted = true; }
+
+		/**
+		 * @brief	Retrieves the value returned by the async operation.
+		 */
+		template <typename T>
+		T getReturnValue() const 
+		{ 
+#if CM_DEBUG_MODE
+			if(!hasCompleted())
+				CM_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
+#endif
+			// Be careful if boost returns bad_any_cast. It doesn't support casting of polymorphic types. Provided and returned
+			// types must be EXACT. (You'll have to cast the data yourself when completing the operation)
+			return boost::any_cast<T>(mData->mReturnValue);
+		}
+
+	private:
+		std::shared_ptr<AsyncOpData> mData;
+	};
+}