瀏覽代碼

More RenderSystemContext related changes, mostly refactoring

Marko Pintera 13 年之前
父節點
當前提交
291f52586c

+ 10 - 22
CamelotD3D9Renderer/Include/CmD3D9RenderSystem.h

@@ -179,9 +179,6 @@ namespace CamelotEngine
 		~D3D9RenderSystem();
 
 		virtual void initConfigOptions();
-
-		// Overridden RenderSystem functions
-		String validateConfigOptions();
 		
 		/**
          * Set current render target to target, enabling its GL context if needed
@@ -193,8 +190,6 @@ namespace CamelotEngine
 
 		String getErrorDescription( long errorNumber ) const;
 		const String& getName() const;
-		// Low-level overridden members
-		void setConfigOption( const String &name, const String &value );
 		void shutdown();
 		void destroyRenderTarget(const String& name);
 		VertexElementType getColorVertexElementType() const;
@@ -235,19 +230,6 @@ namespace CamelotEngine
 		void setVertexDeclaration(VertexDeclarationPtr decl);
 		void setVertexBufferBinding(VertexBufferBinding* binding);
         void render(const RenderOperation& op);
-        /** See
-          RenderSystem
-         */
-        void bindGpuProgram(GpuProgramRef prg);
-        /** See
-          RenderSystem
-         */
-        void unbindGpuProgram(GpuProgramType gptype);
-        /** See
-          RenderSystem
-         */
-		void bindGpuProgramParameters(GpuProgramType gptype, 
-			GpuProgramParametersSharedPtr params, UINT16 variabilityMask);
 
         void setScissorTest(bool enabled, size_t left = 0, size_t top = 0, size_t right = 800, size_t bottom = 600);
         void clearFrameBuffer(unsigned int buffers, 
@@ -259,9 +241,7 @@ namespace CamelotEngine
         float getVerticalTexelOffset();
         float getMinimumDepthInputValue();
         float getMaximumDepthInputValue();
-		void registerThread();
-		void unregisterThread();	
-		
+
 		static D3D9ResourceManager* getResourceManager();
 		static D3D9DeviceManager* getDeviceManager();
 		static IDirect3D9* getDirect3D9();
@@ -305,11 +285,19 @@ namespace CamelotEngine
 		/* 							INTERNAL CALLBACKS                     		*/
 		/************************************************************************/
 	protected:
-		void startUp_internal(AsyncOp& asyncOp);
+		void startUp_internal();
 
 		void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
 			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp);
 
+
+        void bindGpuProgram_internal(GpuProgramRef prg);
+
+        void unbindGpuProgram_internal(GpuProgramType gptype);
+
+		void bindGpuProgramParameters_internal(GpuProgramType gptype, 
+			GpuProgramParametersSharedPtr params, UINT16 variabilityMask);
+
 	protected:	
 		/// Notify when a device has been lost.
 		void notifyOnDeviceLost(D3D9Device* device);

+ 206 - 334
CamelotD3D9Renderer/Source/CmD3D9RenderSystem.cpp

@@ -293,82 +293,6 @@ namespace CamelotEngine
 
 	}
 	//---------------------------------------------------------------------
-	void D3D9RenderSystem::setConfigOption( const String &name, const String &value )
-	{
-		bool viewModeChanged = false;
-
-		// Find option
-		ConfigOptionMap::iterator it = mOptions.find( name );
-
-		// Update
-		if( it != mOptions.end() )
-			it->second.currentValue = value;
-		else
-		{
-			StringUtil::StrStreamType str;
-			str << "Option named '" << name << "' does not exist.";
-			CM_EXCEPT(InvalidParametersException, str.str() );
-		}
-
-		// Refresh other options if D3DDriver changed
-		if( name == "Rendering Device" )
-			refreshD3DSettings();
-
-		if( name == "Full Screen" )
-		{
-			// Video mode is applicable
-			it = mOptions.find( "Video Mode" );
-			if (it->second.currentValue.empty())
-			{
-				it->second.currentValue = "800 x 600 @ 32-bit colour";
-				viewModeChanged = true;
-			}
-		}
-
-		if( name == "FSAA" )
-		{
-			std::vector<CamelotEngine::String> values = StringUtil::split(value, " ", 1);
-			mFSAASamples = parseUnsignedInt(values[0]);
-			if (values.size() > 1)
-				mFSAAHint = values[1];
-
-		}
-
-		if( name == "VSync" )
-		{
-			if (value == "Yes")
-				mVSync = true;
-			else
-				mVSync = false;
-		}
-
-		if( name == "VSync Interval" )
-		{
-			mVSyncInterval = parseUnsignedInt(value);
-		}
-
-		if( name == "Allow NVPerfHUD" )
-		{
-			if (value == "Yes")
-				mUseNVPerfHUD = true;
-			else
-				mUseNVPerfHUD = false;
-		}
-
-		if (viewModeChanged || name == "Video Mode")
-		{
-			refreshFSAAOptions();
-		}
-
-		if (name == "Resource Creation Policy")
-		{
-			if (value == "Create on active device")
-				mResourceManager->setCreationPolicy(RCP_CREATE_ON_ACTIVE_DEVICE);
-			else if (value == "Create on all devices")
-				mResourceManager->setCreationPolicy(RCP_CREATE_ON_ALL_DEVICES);		
-		}
-	}
-	//---------------------------------------------------------------------
 	void D3D9RenderSystem::refreshFSAAOptions()
 	{
 		ConfigOptionMap::iterator it = mOptions.find( "FSAA" );
@@ -419,44 +343,6 @@ namespace CamelotEngine
 
 	}
 	//---------------------------------------------------------------------
-	String D3D9RenderSystem::validateConfigOptions()
-	{
-		ConfigOptionMap::iterator it;
-
-		// check if video mode is selected
-		it = mOptions.find( "Video Mode" );
-		if (it->second.currentValue.empty())
-			return "A video mode must be selected.";
-
-		it = mOptions.find( "Rendering Device" );
-		bool foundDriver = false;
-		D3D9DriverList* driverList = getDirect3DDrivers();
-		for( UINT16 j=0; j < driverList->count(); j++ )
-		{
-			if( driverList->item(j)->DriverDescription() == it->second.currentValue )
-			{
-				foundDriver = true;
-				break;
-			}
-		}
-
-		if (!foundDriver)
-		{
-			// Just pick the first driver
-			setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
-			return "Your DirectX driver name has changed since the last time you ran OGRE; "
-				"the 'Rendering Device' has been changed.";
-		}
-
-		it = mOptions.find( "VSync" );
-		if( it->second.currentValue == "Yes" )
-			mVSync = true;
-		else
-			mVSync = false;
-
-		return StringUtil::BLANK;
-	}
-	//---------------------------------------------------------------------
 	void D3D9RenderSystem::shutdown()
 	{
 		RenderSystem::shutdown();
@@ -473,7 +359,7 @@ namespace CamelotEngine
 	//---------------------------------------------------------------------
 	RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow)
 	{			
-		RenderSystemCapabilities* rsc = mRealCapabilities;
+		RenderSystemCapabilities* rsc = mCurrentCapabilities;
 		if (rsc == NULL)
 			rsc = new RenderSystemCapabilities();
 
@@ -785,16 +671,11 @@ namespace CamelotEngine
 		}
 
 
-		if (mRealCapabilities == NULL)
+		if (mCurrentCapabilities == NULL)
 		{		
-			mRealCapabilities = rsc;
-			mRealCapabilities->addShaderProfile("hlsl");
-			mRealCapabilities->addShaderProfile("cg");
-
-			// if we are using custom capabilities, then 
-			// mCurrentCapabilities has already been loaded
-			if(!mUseCustomCapabilities)
-				mCurrentCapabilities = mRealCapabilities;
+			mCurrentCapabilities = rsc;
+			mCurrentCapabilities->addShaderProfile("hlsl");
+			mCurrentCapabilities->addShaderProfile("cg");
 
 			initialiseFromRenderSystemCapabilities(mCurrentCapabilities, renderWindow);
 		}
@@ -2083,203 +1964,6 @@ namespace CamelotEngine
 
 	}
 	//---------------------------------------------------------------------
-	void D3D9RenderSystem::bindGpuProgram(GpuProgramRef prg)
-	{
-		GpuProgram* bindingPrg = prg->_getBindingDelegate();
-
-		HRESULT hr;
-		switch (bindingPrg->getType())
-		{
-		case GPT_VERTEX_PROGRAM:
-			hr = getActiveD3D9Device()->SetVertexShader(
-				static_cast<D3D9GpuVertexProgram*>(bindingPrg)->getVertexShader());
-			if (FAILED(hr))
-			{
-				CM_EXCEPT(RenderingAPIException, "Error calling SetVertexShader");
-			}
-			break;
-		case GPT_FRAGMENT_PROGRAM:
-			hr = getActiveD3D9Device()->SetPixelShader(
-				static_cast<D3D9GpuFragmentProgram*>(bindingPrg)->getPixelShader());
-			if (FAILED(hr))
-			{
-				CM_EXCEPT(RenderingAPIException, "Error calling SetPixelShader");
-			}
-			break;
-		};
-
-		// Make sure texcoord index is equal to stage value, As SDK Doc suggests:
-		// "When rendering using vertex shaders, each stage's texture coordinate index must be set to its default value."
-		// This solves such an errors when working with the Debug runtime -
-		// "Direct3D9: (ERROR) :Stage 1 - Texture coordinate index in the stage must be equal to the stage index when programmable vertex pipeline is used".
-		for (unsigned int nStage=0; nStage < 8; ++nStage)
-			__SetTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage);
-
-		RenderSystem::bindGpuProgram(prg);
-
-	}
-	//---------------------------------------------------------------------
-	void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
-	{
-		HRESULT hr;
-		switch(gptype)
-		{
-		case GPT_VERTEX_PROGRAM:
-			mActiveVertexGpuProgramParameters = nullptr;
-			hr = getActiveD3D9Device()->SetVertexShader(NULL);
-			if (FAILED(hr))
-			{
-				CM_EXCEPT(RenderingAPIException, "Error resetting SetVertexShader to NULL");
-			}
-			break;
-		case GPT_FRAGMENT_PROGRAM:
-			mActiveFragmentGpuProgramParameters = nullptr;
-			hr = getActiveD3D9Device()->SetPixelShader(NULL);
-			if (FAILED(hr))
-			{
-				CM_EXCEPT(RenderingAPIException, "Error resetting SetPixelShader to NULL");
-			}
-			break;
-		};
-		RenderSystem::unbindGpuProgram(gptype);
-	}
-	//---------------------------------------------------------------------
-	void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 
-		GpuProgramParametersSharedPtr params, UINT16 variability)
-	{
-		HRESULT hr;
-		GpuLogicalBufferStructPtr floatLogical = params->getFloatLogicalBufferStruct();
-		GpuLogicalBufferStructPtr intLogical = params->getIntLogicalBufferStruct();
-
-		GpuLogicalBufferStructPtr samplerLogical = params->getSamplerLogicalBufferStruct();
-
-		// Set texture sampler
-		{
-			CM_LOCK_MUTEX(samplerLogical->mutex)
-
-			for (GpuLogicalIndexUseMap::const_iterator i = samplerLogical->map.begin();
-				i != samplerLogical->map.end(); ++i)
-			{
-				if (i->second.variability & variability)
-				{
-					size_t logicalIndex = i->first;
-					TextureRef texture = params->getTexture(i->second.physicalIndex);
-
-					const SamplerState& samplerState = params->getSamplerState(i->second.physicalIndex);
-
-					setTextureUnitSettings(logicalIndex, texture.getInternalPtr(), samplerState);
-				}
-			}
-		}
-
-		switch(gptype)
-		{
-		case GPT_VERTEX_PROGRAM:
-			mActiveVertexGpuProgramParameters = params;
-			{
-				CM_LOCK_MUTEX(floatLogical->mutex)
-
-					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
-						i != floatLogical->map.end(); ++i)
-					{
-						if (i->second.variability & variability)
-						{
-							size_t logicalIndex = i->first;
-							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
-							size_t slotCount = i->second.currentSize / 4;
-							assert (i->second.currentSize % 4 == 0 && "Should not have any "
-								"elements less than 4 wide for D3D9");
-
-						if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF( // TODO Low priority. Binding parameters 1 by 1 is slow. It would be better to keep them in a sequential
-							(UINT)logicalIndex, pFloat, (UINT)slotCount)))               // buffer and then only call this method once
-							{
-								CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader float parameters");
-							}
-						}
-
-					}
-
-			}
-			// bind ints
-			{
-				CM_LOCK_MUTEX(intLogical->mutex)
-
-					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
-						i != intLogical->map.end(); ++i)
-					{
-						if (i->second.variability & variability)
-						{
-							size_t logicalIndex = i->first;
-							const int* pInt = params->getIntPointer(i->second.physicalIndex);
-							size_t slotCount = i->second.currentSize / 4;
-							assert (i->second.currentSize % 4 == 0 && "Should not have any "
-								"elements less than 4 wide for D3D9");
-
-						if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantI(
-							static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
-							{
-								CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader int parameters");
-							}
-						}
-					}
-
-			}
-
-			break;
-		case GPT_FRAGMENT_PROGRAM:
-			mActiveFragmentGpuProgramParameters = params;
-			{
-				CM_LOCK_MUTEX(floatLogical->mutex)
-
-					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
-						i != floatLogical->map.end(); ++i)
-					{
-						if (i->second.variability & variability)
-						{
-							size_t logicalIndex = i->first;
-							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
-							size_t slotCount = i->second.currentSize / 4;
-							assert (i->second.currentSize % 4 == 0 && "Should not have any "
-								"elements less than 4 wide for D3D9");
-
-						if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF(
-							static_cast<UINT>(logicalIndex), pFloat, static_cast<UINT>(slotCount))))
-							{
-								CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader float parameters");
-							}
-						}
-					}
-
-			}
-			// bind ints
-			{
-				CM_LOCK_MUTEX(intLogical->mutex)
-
-					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
-						i != intLogical->map.end(); ++i)
-					{
-						if (i->second.variability & variability)
-						{
-							size_t logicalIndex = i->first;
-							const int* pInt = params->getIntPointer(i->second.physicalIndex);
-							size_t slotCount = i->second.currentSize / 4;
-							assert (i->second.currentSize % 4 == 0 && "Should not have any "
-								"elements less than 4 wide for D3D9");
-
-						if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantI(
-							static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
-							{
-								CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader int parameters");
-							}
-						}
-
-					}
-
-			}
-			break;
-		};
-	}
-	//---------------------------------------------------------------------
 	void D3D9RenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes)
 	{
 		size_t i;
@@ -2638,16 +2322,6 @@ namespace CamelotEngine
 		}		
 	}
 	//---------------------------------------------------------------------
-	void D3D9RenderSystem::registerThread()
-	{
-		// nothing to do - D3D9 shares rendering context already
-	}
-	//---------------------------------------------------------------------
-	void D3D9RenderSystem::unregisterThread()
-	{
-		// nothing to do - D3D9 shares rendering context already
-	}
-	//---------------------------------------------------------------------
 	D3D9ResourceManager* D3D9RenderSystem::getResourceManager()
 	{
 		return msD3D9RenderSystem->mResourceManager;
@@ -2662,7 +2336,7 @@ namespace CamelotEngine
 	//---------------------------------------------------------------------
 	RenderSystemCapabilities* D3D9RenderSystem::createRenderSystemCapabilities() const
 	{
-		return mRealCapabilities;
+		return mCurrentCapabilities;
 	}
 
 	//---------------------------------------------------------------------
@@ -2846,7 +2520,7 @@ namespace CamelotEngine
 	/************************************************************************/
 	/* 							INTERNAL CALLBACKS                     		*/
 	/************************************************************************/
-	void D3D9RenderSystem::startUp_internal(AsyncOp& asyncOp)
+	void D3D9RenderSystem::startUp_internal()
 	{
 		// Create the resource manager.
 		mResourceManager = new D3D9ResourceManager();
@@ -2918,7 +2592,7 @@ namespace CamelotEngine
 		mCgProgramFactory = new CgProgramFactory();
 
 		// call superclass method
-		RenderSystem::startUp_internal(asyncOp);
+		RenderSystem::startUp_internal();
 	}
 
 	void D3D9RenderSystem::createRenderWindow_internal(const String &name, 
@@ -2966,4 +2640,202 @@ namespace CamelotEngine
 
 		asyncOp.completeOperation(static_cast<RenderWindow*>(renderWindow));
 	}	
+
+	void D3D9RenderSystem::bindGpuProgram_internal(GpuProgramRef prg)
+	{
+		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+
+		HRESULT hr;
+		switch (bindingPrg->getType())
+		{
+		case GPT_VERTEX_PROGRAM:
+			hr = getActiveD3D9Device()->SetVertexShader(
+				static_cast<D3D9GpuVertexProgram*>(bindingPrg)->getVertexShader());
+			if (FAILED(hr))
+			{
+				CM_EXCEPT(RenderingAPIException, "Error calling SetVertexShader");
+			}
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			hr = getActiveD3D9Device()->SetPixelShader(
+				static_cast<D3D9GpuFragmentProgram*>(bindingPrg)->getPixelShader());
+			if (FAILED(hr))
+			{
+				CM_EXCEPT(RenderingAPIException, "Error calling SetPixelShader");
+			}
+			break;
+		};
+
+		// Make sure texcoord index is equal to stage value, As SDK Doc suggests:
+		// "When rendering using vertex shaders, each stage's texture coordinate index must be set to its default value."
+		// This solves such an errors when working with the Debug runtime -
+		// "Direct3D9: (ERROR) :Stage 1 - Texture coordinate index in the stage must be equal to the stage index when programmable vertex pipeline is used".
+		for (unsigned int nStage=0; nStage < 8; ++nStage)
+			__SetTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage);
+
+		RenderSystem::bindGpuProgram_internal(prg);
+
+	}
+
+	void D3D9RenderSystem::unbindGpuProgram_internal(GpuProgramType gptype)
+	{
+		HRESULT hr;
+		switch(gptype)
+		{
+		case GPT_VERTEX_PROGRAM:
+			mActiveVertexGpuProgramParameters = nullptr;
+			hr = getActiveD3D9Device()->SetVertexShader(NULL);
+			if (FAILED(hr))
+			{
+				CM_EXCEPT(RenderingAPIException, "Error resetting SetVertexShader to NULL");
+			}
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			mActiveFragmentGpuProgramParameters = nullptr;
+			hr = getActiveD3D9Device()->SetPixelShader(NULL);
+			if (FAILED(hr))
+			{
+				CM_EXCEPT(RenderingAPIException, "Error resetting SetPixelShader to NULL");
+			}
+			break;
+		};
+
+		RenderSystem::unbindGpuProgram_internal(gptype);
+	}
+
+	void D3D9RenderSystem::bindGpuProgramParameters_internal(GpuProgramType gptype, 
+		GpuProgramParametersSharedPtr params, UINT16 variability)
+	{
+		HRESULT hr;
+		GpuLogicalBufferStructPtr floatLogical = params->getFloatLogicalBufferStruct();
+		GpuLogicalBufferStructPtr intLogical = params->getIntLogicalBufferStruct();
+
+		GpuLogicalBufferStructPtr samplerLogical = params->getSamplerLogicalBufferStruct();
+
+		// Set texture sampler
+		{
+			CM_LOCK_MUTEX(samplerLogical->mutex)
+
+				for (GpuLogicalIndexUseMap::const_iterator i = samplerLogical->map.begin();
+					i != samplerLogical->map.end(); ++i)
+				{
+					if (i->second.variability & variability)
+					{
+						size_t logicalIndex = i->first;
+						TextureRef texture = params->getTexture(i->second.physicalIndex);
+
+						const SamplerState& samplerState = params->getSamplerState(i->second.physicalIndex);
+
+						setTextureUnitSettings(logicalIndex, texture.getInternalPtr(), samplerState);
+					}
+				}
+		}
+
+		switch(gptype)
+		{
+		case GPT_VERTEX_PROGRAM:
+			mActiveVertexGpuProgramParameters = params;
+			{
+				CM_LOCK_MUTEX(floatLogical->mutex)
+
+					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
+						i != floatLogical->map.end(); ++i)
+					{
+						if (i->second.variability & variability)
+						{
+							size_t logicalIndex = i->first;
+							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
+							size_t slotCount = i->second.currentSize / 4;
+							assert (i->second.currentSize % 4 == 0 && "Should not have any "
+								"elements less than 4 wide for D3D9");
+
+							if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF( // TODO Low priority. Binding parameters 1 by 1 is slow. It would be better to keep them in a sequential
+								(UINT)logicalIndex, pFloat, (UINT)slotCount)))               // buffer and then only call this method once
+							{
+								CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader float parameters");
+							}
+						}
+
+					}
+
+			}
+			// bind ints
+			{
+				CM_LOCK_MUTEX(intLogical->mutex)
+
+					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
+						i != intLogical->map.end(); ++i)
+					{
+						if (i->second.variability & variability)
+						{
+							size_t logicalIndex = i->first;
+							const int* pInt = params->getIntPointer(i->second.physicalIndex);
+							size_t slotCount = i->second.currentSize / 4;
+							assert (i->second.currentSize % 4 == 0 && "Should not have any "
+								"elements less than 4 wide for D3D9");
+
+							if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantI(
+								static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
+							{
+								CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader int parameters");
+							}
+						}
+					}
+
+			}
+
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			mActiveFragmentGpuProgramParameters = params;
+			{
+				CM_LOCK_MUTEX(floatLogical->mutex)
+
+					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
+						i != floatLogical->map.end(); ++i)
+					{
+						if (i->second.variability & variability)
+						{
+							size_t logicalIndex = i->first;
+							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
+							size_t slotCount = i->second.currentSize / 4;
+							assert (i->second.currentSize % 4 == 0 && "Should not have any "
+								"elements less than 4 wide for D3D9");
+
+							if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF(
+								static_cast<UINT>(logicalIndex), pFloat, static_cast<UINT>(slotCount))))
+							{
+								CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader float parameters");
+							}
+						}
+					}
+
+			}
+			// bind ints
+			{
+				CM_LOCK_MUTEX(intLogical->mutex)
+
+					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
+						i != intLogical->map.end(); ++i)
+					{
+						if (i->second.variability & variability)
+						{
+							size_t logicalIndex = i->first;
+							const int* pInt = params->getIntPointer(i->second.physicalIndex);
+							size_t slotCount = i->second.currentSize / 4;
+							assert (i->second.currentSize % 4 == 0 && "Should not have any "
+								"elements less than 4 wide for D3D9");
+
+							if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantI(
+								static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
+							{
+								CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader int parameters");
+							}
+						}
+
+					}
+
+			}
+			break;
+		};
+	}
 }

+ 14 - 32
CamelotGLRenderer/Include/CmGLRenderSystem.h

@@ -73,7 +73,16 @@ namespace CamelotEngine {
  
         GLint getBlendMode(SceneBlendFactor ogreBlend) const;
 		GLint getTextureAddressingMode(SamplerState::TextureAddressingMode tam) const;
-				void initialiseContext(RenderWindow* primary);
+		void initialiseContext(RenderWindow* primary);
+
+		/** See
+          RenderSystem
+         */
+		virtual RenderSystemCapabilities* createRenderSystemCapabilities() const;
+        /** See
+          RenderSystem
+         */
+		void initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary);
 
         /// Store last depth write state
         bool mDepthWrite;
@@ -122,11 +131,14 @@ namespace CamelotEngine {
 		/* 							INTERNAL CALLBACKS                     		*/
 		/************************************************************************/
 	protected:
-        void startUp_internal(AsyncOp& asyncOp);
+        void startUp_internal();
 
 		void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
 			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp);
 
+        void bindGpuProgram_internal(GpuProgramRef prg);
+        void unbindGpuProgram_internal(GpuProgramType gptype);
+		void bindGpuProgramParameters_internal(GpuProgramType gptype, GpuProgramParametersSharedPtr params, UINT16 mask);
 	protected:
 		void setClipPlanesImpl(const PlaneList& clipPlanes);
 		bool activateGLTextureUnit(size_t unit);
@@ -142,26 +154,6 @@ namespace CamelotEngine {
           RenderSystem
          */
         const String& getName(void) const;
-        /** See
-          RenderSystem
-         */
-        ConfigOptionMap& getConfigOptions(void);
-        /** See
-          RenderSystem
-         */
-        void setConfigOption(const String &name, const String &value);
-        /** See
-          RenderSystem
-         */
-        String validateConfigOptions(void);
-        /** See
-          RenderSystem
-         */
-				virtual RenderSystemCapabilities* createRenderSystemCapabilities() const;
-        /** See
-          RenderSystem
-         */
-				void initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary);
         /** See
           RenderSystem
          */
@@ -318,14 +310,6 @@ namespace CamelotEngine {
           RenderSystem
          */
         void render(const RenderOperation& op);
-        /** See
-          RenderSystem
-         */
-        void bindGpuProgram(GpuProgramRef prg);
-        /** See
-          RenderSystem
-         */
-        void unbindGpuProgram(GpuProgramType gptype);
         /** See
           RenderSystem
          */
@@ -343,8 +327,6 @@ namespace CamelotEngine {
         float getMinimumDepthInputValue(void);
         float getMaximumDepthInputValue(void);
 		CM_MUTEX(mThreadInitMutex)
-		void registerThread();
-		void unregisterThread();
 
         // ----------------------------------
         // GLRenderSystem specific members

+ 126 - 197
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -140,22 +140,6 @@ namespace CamelotEngine {
 		mGLSupport->addConfig();
 	}
 
-	ConfigOptionMap& GLRenderSystem::getConfigOptions(void)
-	{
-		return mGLSupport->getConfigOptions();
-	}
-
-	void GLRenderSystem::setConfigOption(const String &name, const String &value)
-	{
-		mGLSupport->setConfigOption(name, value);
-	}
-
-	String GLRenderSystem::validateConfigOptions(void)
-	{
-		// XXX Return an error string if something is invalid
-		return mGLSupport->validateConfig();
-	}
-
 	RenderSystemCapabilities* GLRenderSystem::createRenderSystemCapabilities() const
 	{
 		RenderSystemCapabilities* rsc = new RenderSystemCapabilities();
@@ -785,26 +769,8 @@ namespace CamelotEngine {
 			}
 		}
 
-
-		/// Do this after extension function pointers are initialised as the extension
-		/// is used to probe further capabilities.
-		ConfigOptionMap::iterator cfi = getConfigOptions().find("RTT Preferred Mode");
 		// RTT Mode: 0 use whatever available, 1 use PBuffers, 2 force use copying
 		int rttMode = 0;
-		if (cfi != getConfigOptions().end())
-		{
-			if (cfi->second.currentValue == "PBuffer")
-			{
-				rttMode = 1;
-			}
-			else if (cfi->second.currentValue == "Copy")
-			{
-				rttMode = 2;
-			}
-		}
-
-
-
 
 		// Check for framebuffer object extension
 		if(caps->hasCapability(RSC_FBO) && rttMode < 1)
@@ -2013,128 +1979,6 @@ namespace CamelotEngine {
 
 	}
 	//---------------------------------------------------------------------
-	void GLRenderSystem::bindGpuProgram(GpuProgramRef prg)
-	{
-		GpuProgram* bindingPrg = prg->_getBindingDelegate();
-		GLGpuProgram* glprg = static_cast<GLGpuProgram*>(bindingPrg);
-
-		// Unbind previous gpu program first.
-		//
-		// Note:
-		//  1. Even if both previous and current are the same object, we can't
-		//     bypass re-bind completely since the object itself maybe modified.
-		//     But we can bypass unbind based on the assumption that object
-		//     internally GL program type shouldn't be changed after it has
-		//     been created. The behavior of bind to a GL program type twice
-		//     should be same as unbind and rebind that GL program type, even
-		//     for difference objects.
-		//  2. We also assumed that the program's type (vertex or fragment) should
-		//     not be changed during it's in using. If not, the following switch
-		//     statement will confuse GL state completely, and we can't fix it
-		//     here. To fix this case, we must coding the program implementation
-		//     itself, if type is changing (during load/unload, etc), and it's inuse,
-		//     unbind and notify render system to correct for its state.
-		//
-		switch (glprg->getType())
-		{
-		case GPT_VERTEX_PROGRAM:
-			if (mCurrentVertexProgram != glprg)
-			{
-				if (mCurrentVertexProgram)
-					mCurrentVertexProgram->unbindProgram();
-				mCurrentVertexProgram = glprg;
-			}
-			break;
-
-		case GPT_FRAGMENT_PROGRAM:
-			if (mCurrentFragmentProgram != glprg)
-			{
-				if (mCurrentFragmentProgram)
-					mCurrentFragmentProgram->unbindProgram();
-				mCurrentFragmentProgram = glprg;
-			}
-			break;
-		case GPT_GEOMETRY_PROGRAM:
-			if (mCurrentGeometryProgram != glprg)
-			{
-				if (mCurrentGeometryProgram)
-					mCurrentGeometryProgram->unbindProgram();
-				mCurrentGeometryProgram = glprg;
-			}
-			break;
-		}
-
-		// Bind the program
-		glprg->bindProgram();
-
-		RenderSystem::bindGpuProgram(prg);
-	}
-	//---------------------------------------------------------------------
-	void GLRenderSystem::unbindGpuProgram(GpuProgramType gptype)
-	{
-
-		if (gptype == GPT_VERTEX_PROGRAM && mCurrentVertexProgram)
-		{
-			mActiveVertexGpuProgramParameters = nullptr;
-			mCurrentVertexProgram->unbindProgram();
-			mCurrentVertexProgram = 0;
-		}
-		else if (gptype == GPT_GEOMETRY_PROGRAM && mCurrentGeometryProgram)
-		{
-			mActiveGeometryGpuProgramParameters = nullptr;
-			mCurrentGeometryProgram->unbindProgram();
-			mCurrentGeometryProgram = 0;
-		}
-		else if (gptype == GPT_FRAGMENT_PROGRAM && mCurrentFragmentProgram)
-		{
-			mActiveFragmentGpuProgramParameters = nullptr;
-			mCurrentFragmentProgram->unbindProgram();
-			mCurrentFragmentProgram = 0;
-		}
-		RenderSystem::unbindGpuProgram(gptype);
-
-	}
-	//---------------------------------------------------------------------
-	void GLRenderSystem::bindGpuProgramParameters(GpuProgramType gptype, GpuProgramParametersSharedPtr params, UINT16 mask)
-	{
-		// Set textures
-		const GpuNamedConstants& consts = params->getConstantDefinitions();
-		for(auto iter = consts.map.begin(); iter != consts.map.end(); ++iter)
-		{
-			const GpuConstantDefinition& def = iter->second;
-
-			if(def.variability & mask)
-			{
-				if(def.constType == GCT_SAMPLER2D || def.constType == GCT_SAMPLERCUBE || def.constType == GCT_SAMPLER1D 
-					|| def.constType == GCT_SAMPLER2DSHADOW || def.constType == GCT_SAMPLER3D || def.constType == GCT_SAMPLER1DSHADOW)
-				{
-					TextureRef curTexture = params->getTexture(def.physicalIndex);
-					setTexture(def.physicalIndex, true, curTexture.getInternalPtr());
-
-					const SamplerState& samplerState = params->getSamplerState(def.physicalIndex);
-
-					setTextureUnitSettings(def.physicalIndex, curTexture.getInternalPtr(), samplerState);
-				}
-			}
-		}
-
-		switch (gptype)
-		{
-		case GPT_VERTEX_PROGRAM:
-			mActiveVertexGpuProgramParameters = params;
-			mCurrentVertexProgram->bindProgramParameters(params, mask);
-			break;
-		case GPT_GEOMETRY_PROGRAM:
-			mActiveGeometryGpuProgramParameters = params;
-			mCurrentGeometryProgram->bindProgramParameters(params, mask);
-			break;
-		case GPT_FRAGMENT_PROGRAM:
-			mActiveFragmentGpuProgramParameters = params;
-			mCurrentFragmentProgram->bindProgramParameters(params, mask);
-			break;
-		}
-	}
-	//---------------------------------------------------------------------
 	void GLRenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes)
 	{
 		// A note on GL user clipping:
@@ -2464,40 +2308,6 @@ namespace CamelotEngine {
 		return 1.0f;
 	}
 	//---------------------------------------------------------------------
-	void GLRenderSystem::registerThread()
-	{
-		CM_LOCK_MUTEX(mThreadInitMutex)
-		// This is only valid once we've created the main context
-		if (!mMainContext)
-		{
-			CM_EXCEPT(InvalidParametersException, 
-				"Cannot register a background thread before the main context has been created.");
-		}
-
-		// Create a new context for this thread. Cloning from the main context
-		// will ensure that resources are shared with the main context
-		// We want a separate context so that we can safely create GL
-		// objects in parallel with the main thread
-		GLContext* newContext = mMainContext->clone();
-		mBackgroundContextList.push_back(newContext);
-
-		// Bind this new context to this thread. 
-		newContext->setCurrent();
-
-		_oneTimeContextInitialization();
-		newContext->setInitialized();
-
-
-	}
-	//---------------------------------------------------------------------
-	void GLRenderSystem::unregisterThread()
-	{
-		// nothing to do here?
-		// Don't need to worry about active context, just make sure we delete
-		// on shutdown.
-
-	}
-	//---------------------------------------------------------------------
 	bool GLRenderSystem::activateGLTextureUnit(size_t unit)
 	{
 		if (mActiveTextureUnit != unit)
@@ -2534,11 +2344,11 @@ namespace CamelotEngine {
 	/* 							INTERNAL CALLBACKS                     		*/
 	/************************************************************************/
 
-	void GLRenderSystem::startUp_internal(AsyncOp& asyncOp)
+	void GLRenderSystem::startUp_internal()
 	{
 		mGLSupport->start();
 
-		RenderSystem::startUp_internal(asyncOp);
+		RenderSystem::startUp_internal();
 	}
 
 	void GLRenderSystem::createRenderWindow_internal(const String &name, 
@@ -2576,11 +2386,7 @@ namespace CamelotEngine {
 			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;
+			mCurrentCapabilities = createRenderSystemCapabilities();
 
 			initialiseFromRenderSystemCapabilities(mCurrentCapabilities, win);
 
@@ -2592,4 +2398,127 @@ namespace CamelotEngine {
 
 		asyncOp.completeOperation(win);
 	}
+
+	//---------------------------------------------------------------------
+	void GLRenderSystem::bindGpuProgram_internal(GpuProgramRef prg)
+	{
+		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+		GLGpuProgram* glprg = static_cast<GLGpuProgram*>(bindingPrg);
+
+		// Unbind previous gpu program first.
+		//
+		// Note:
+		//  1. Even if both previous and current are the same object, we can't
+		//     bypass re-bind completely since the object itself maybe modified.
+		//     But we can bypass unbind based on the assumption that object
+		//     internally GL program type shouldn't be changed after it has
+		//     been created. The behavior of bind to a GL program type twice
+		//     should be same as unbind and rebind that GL program type, even
+		//     for difference objects.
+		//  2. We also assumed that the program's type (vertex or fragment) should
+		//     not be changed during it's in using. If not, the following switch
+		//     statement will confuse GL state completely, and we can't fix it
+		//     here. To fix this case, we must coding the program implementation
+		//     itself, if type is changing (during load/unload, etc), and it's inuse,
+		//     unbind and notify render system to correct for its state.
+		//
+		switch (glprg->getType())
+		{
+		case GPT_VERTEX_PROGRAM:
+			if (mCurrentVertexProgram != glprg)
+			{
+				if (mCurrentVertexProgram)
+					mCurrentVertexProgram->unbindProgram();
+				mCurrentVertexProgram = glprg;
+			}
+			break;
+
+		case GPT_FRAGMENT_PROGRAM:
+			if (mCurrentFragmentProgram != glprg)
+			{
+				if (mCurrentFragmentProgram)
+					mCurrentFragmentProgram->unbindProgram();
+				mCurrentFragmentProgram = glprg;
+			}
+			break;
+		case GPT_GEOMETRY_PROGRAM:
+			if (mCurrentGeometryProgram != glprg)
+			{
+				if (mCurrentGeometryProgram)
+					mCurrentGeometryProgram->unbindProgram();
+				mCurrentGeometryProgram = glprg;
+			}
+			break;
+		}
+
+		// Bind the program
+		glprg->bindProgram();
+
+		RenderSystem::bindGpuProgram_internal(prg);
+	}
+	//---------------------------------------------------------------------
+	void GLRenderSystem::unbindGpuProgram_internal(GpuProgramType gptype)
+	{
+
+		if (gptype == GPT_VERTEX_PROGRAM && mCurrentVertexProgram)
+		{
+			mActiveVertexGpuProgramParameters = nullptr;
+			mCurrentVertexProgram->unbindProgram();
+			mCurrentVertexProgram = 0;
+		}
+		else if (gptype == GPT_GEOMETRY_PROGRAM && mCurrentGeometryProgram)
+		{
+			mActiveGeometryGpuProgramParameters = nullptr;
+			mCurrentGeometryProgram->unbindProgram();
+			mCurrentGeometryProgram = 0;
+		}
+		else if (gptype == GPT_FRAGMENT_PROGRAM && mCurrentFragmentProgram)
+		{
+			mActiveFragmentGpuProgramParameters = nullptr;
+			mCurrentFragmentProgram->unbindProgram();
+			mCurrentFragmentProgram = 0;
+		}
+		RenderSystem::unbindGpuProgram_internal(gptype);
+
+	}
+
+	void GLRenderSystem::bindGpuProgramParameters_internal(GpuProgramType gptype, GpuProgramParametersSharedPtr params, UINT16 mask)
+	{
+		// Set textures
+		const GpuNamedConstants& consts = params->getConstantDefinitions();
+		for(auto iter = consts.map.begin(); iter != consts.map.end(); ++iter)
+		{
+			const GpuConstantDefinition& def = iter->second;
+
+			if(def.variability & mask)
+			{
+				if(def.constType == GCT_SAMPLER2D || def.constType == GCT_SAMPLERCUBE || def.constType == GCT_SAMPLER1D 
+					|| def.constType == GCT_SAMPLER2DSHADOW || def.constType == GCT_SAMPLER3D || def.constType == GCT_SAMPLER1DSHADOW)
+				{
+					TextureRef curTexture = params->getTexture(def.physicalIndex);
+					setTexture(def.physicalIndex, true, curTexture.getInternalPtr());
+
+					const SamplerState& samplerState = params->getSamplerState(def.physicalIndex);
+
+					setTextureUnitSettings(def.physicalIndex, curTexture.getInternalPtr(), samplerState);
+				}
+			}
+		}
+
+		switch (gptype)
+		{
+		case GPT_VERTEX_PROGRAM:
+			mActiveVertexGpuProgramParameters = params;
+			mCurrentVertexProgram->bindProgramParameters(params, mask);
+			break;
+		case GPT_GEOMETRY_PROGRAM:
+			mActiveGeometryGpuProgramParameters = params;
+			mCurrentGeometryProgram->bindProgramParameters(params, mask);
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			mActiveFragmentGpuProgramParameters = params;
+			mCurrentFragmentProgram->bindProgramParameters(params, mask);
+			break;
+		}
+	}
 }

+ 75 - 112
CamelotRenderer/Include/CmRenderSystem.h

@@ -135,33 +135,6 @@ namespace CamelotEngine
 		*/
 		virtual const String& getName(void) const = 0;
 
-		/** Sets an option for this API
-		@remarks
-		Used to confirm the settings (normally chosen by the user) in
-		order to make the renderer able to initialise with the settings as required.
-		This may be video mode, D3D driver, full screen / windowed etc.
-		Called automatically by the default configuration
-		dialog, and by the restoration of saved settings.
-		These settings are stored and only activated when
-		RenderSystem::initialise or RenderSystem::reinitialise
-		are called.
-		@par
-		If using a custom configuration dialog, it is advised that the
-		caller calls RenderSystem::getConfigOptions
-		again, since some options can alter resulting from a selection.
-		@param
-		name The name of the option to alter.
-		@param
-		value The value to set the option to.
-		*/
-		virtual void setConfigOption(const String &name, const String &value) = 0;
-
-		/** Validates the options set for the rendering system, returning a message if there are problems.
-		@note
-		If the returned string is empty, there are no problems.
-		*/
-		virtual String validateConfigOptions(void) = 0;
-
 		 /* @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.  
 		 *
@@ -171,18 +144,6 @@ namespace CamelotEngine
 		 */
 		void startUp();
 
-
-		/** Query the real capabilities of the GPU and driver in the RenderSystem*/
-		virtual RenderSystemCapabilities* createRenderSystemCapabilities() const = 0;
-
-		/** Force the render system to use the special capabilities. Can only be called
-		*    before the render system has been fully initializer (before createWindow is called) 
-		*	@param
-		*		 capabilities has to be a subset of the real capabilities and the caller is 
-		*		 responsible for deallocating capabilities.
-		*/
-		virtual void useCustomRenderSystemCapabilities(RenderSystemCapabilities* capabilities);
-
 		/** Shutdown the renderer and cleanup resources.
 		*/
 		virtual void shutdown(void);
@@ -670,37 +631,7 @@ namespace CamelotEngine
 		*/
 		virtual void setDepthBias(float constantBias, float slopeScaleBias = 0.0f) = 0;
 
-		/** The RenderSystem will keep a count of tris rendered, this resets the count. */
-		virtual void beginGeometryCount(void);
-		/** Reports the number of tris rendered since the last _beginGeometryCount call. */
-		virtual unsigned int getFaceCount(void) const;
-		/** Reports the number of batches rendered since the last _beginGeometryCount call. */
-		virtual unsigned int getBatchCount(void) const;
-		/** Reports the number of vertices passed to the renderer since the last _beginGeometryCount call. */
-		virtual unsigned int getVertexCount(void) const;
-
-		/** Generates a packed data version of the passed in ColourValue suitable for
-		use as with this RenderSystem.
-		@remarks
-		Since different render systems have different colour data formats (eg
-		RGBA for GL, ARGB for D3D) this method allows you to use 1 method for all.
-		@param colour The colour to convert
-		@param pDest Pointer to location to put the result.
-		*/
-		virtual void convertColorValue(const Color& colour, UINT32* pDest);
-		/** Get the native VertexElementType for a compact 32-bit colour value
-		for this rendersystem.
-		*/
-		virtual VertexElementType getColorVertexElementType(void) const = 0;
-
-		/** Converts a uniform projection matrix to suitable for this render system.
-		@remarks
-		Because different APIs have different requirements (some incompatible) for the
-		projection matrix, this method allows each to implement their own correctly and pass
-		back a generic Camelot matrix for storage in the engine.
-		*/
-		virtual void _convertProjectionMatrix(const Matrix4& matrix,
-			Matrix4& dest, bool forGpuProgram = false) = 0;
+		
 
 		/** Sets how to rasterise triangles, as points, wireframe or solid polys. */
 		virtual void setPolygonMode(PolygonMode level) = 0;
@@ -804,21 +735,21 @@ namespace CamelotEngine
 		@remarks Only one GpuProgram of each type can be bound at once, binding another
 		one will simply replace the existing one.
 		*/
-		virtual void bindGpuProgram(GpuProgramRef prg);
+		void bindGpuProgram(GpuProgramRef prg);
 
 		/** Bind Gpu program parameters.
 		@param gptype The type of program to bind the parameters to
 		@param params The parameters to bind
 		@param variabilityMask A mask of GpuParamVariability identifying which params need binding
 		*/
-		virtual void bindGpuProgramParameters(GpuProgramType gptype, 
-			GpuProgramParametersSharedPtr params, UINT16 variabilityMask) = 0;
+		void bindGpuProgramParameters(GpuProgramType gptype, 
+			GpuProgramParametersSharedPtr params, UINT16 variabilityMask);
 
 		/** Unbinds GpuPrograms of a given GpuProgramType.
 		@remarks
 		This returns the pipeline to fixed-function processing for this type.
 		*/
-		virtual void unbindGpuProgram(GpuProgramType gptype);
+		void unbindGpuProgram(GpuProgramType gptype);
 
 		/** Returns whether or not a Gpu program of the given type is currently bound. */
 		virtual bool isGpuProgramBound(GpuProgramType gptype);
@@ -838,7 +769,8 @@ namespace CamelotEngine
 
 		/** Internal method for swapping all the buffers on all render targets,
 		if _updateAllRenderTargets was called with a 'false' parameter. */
-		virtual void swapAllRenderTargetBuffers(bool waitForVsync = true);
+		void swapAllRenderTargetBuffers(bool waitForVsync = true);
+		virtual void swapAllRenderTargetBuffers_internal(bool waitForVsync = true);
 
 		/** Sets whether or not vertex windings set should be inverted; this can be important
 		for rendering reflections. */
@@ -873,6 +805,46 @@ namespace CamelotEngine
 		virtual void clearFrameBuffer(unsigned int buffers, 
 			const Color& colour = Color::Black, 
 			float depth = 1.0f, unsigned short stencil = 0) = 0;
+
+		/**
+         * Set current render target to target, enabling its device context if needed
+         */
+        virtual void setRenderTarget(RenderTarget *target) = 0;
+
+		/**
+		* Gets the number of display monitors.
+		@see Root::getDisplayMonitorCount
+		*/
+		virtual unsigned int getDisplayMonitorCount() const = 0;
+
+		/************************************************************************/
+		/* 								UTILITY METHODS                    		*/
+		/************************************************************************/
+
+		/** Generates a packed data version of the passed in ColourValue suitable for
+		use as with this RenderSystem.
+		@remarks
+		Since different render systems have different colour data formats (eg
+		RGBA for GL, ARGB for D3D) this method allows you to use 1 method for all.
+		@param colour The colour to convert
+		@param pDest Pointer to location to put the result.
+		*/
+		virtual void convertColorValue(const Color& colour, UINT32* pDest);
+
+		/** Get the native VertexElementType for a compact 32-bit colour value
+		for this rendersystem.
+		*/
+		virtual VertexElementType getColorVertexElementType(void) const = 0;
+
+		/** Converts a uniform projection matrix to suitable for this render system.
+		@remarks
+		Because different APIs have different requirements (some incompatible) for the
+		projection matrix, this method allows each to implement their own correctly and pass
+		back a generic Camelot matrix for storage in the engine.
+		*/
+		virtual void _convertProjectionMatrix(const Matrix4& matrix,
+			Matrix4& dest, bool forGpuProgram = false) = 0;
+
 		/** Returns the horizontal texel offset value required for mapping 
 		texel origins to pixel origins in this rendersystem.
 		@remarks
@@ -883,6 +855,7 @@ namespace CamelotEngine
 		the horizontal direction.
 		*/
 		virtual float getHorizontalTexelOffset(void) = 0;
+
 		/** Returns the vertical texel offset value required for mapping 
 		texel origins to pixel origins in this rendersystem.
 		@remarks
@@ -903,6 +876,7 @@ namespace CamelotEngine
 		@see Renderable::getUseIdentityView, Renderable::getUseIdentityProjection
 		*/
 		virtual float getMinimumDepthInputValue(void) = 0;
+
 		/** Gets the maximum (farthest) depth value to be used when rendering
 		using identity transforms.
 		@remarks
@@ -913,43 +887,24 @@ namespace CamelotEngine
 		*/
 		virtual float getMaximumDepthInputValue(void) = 0;
 
-		/**
-         * Set current render target to target, enabling its device context if needed
-         */
-        virtual void setRenderTarget(RenderTarget *target) = 0;
-
-		/** Register the an additional thread which may make calls to rendersystem-related 
-		objects.
-		@remarks
-		This method should only be called by additional threads during their
-		initialisation. If they intend to use hardware rendering system resources 
-		they should call this method before doing anything related to the render system.
-		Some rendering APIs require a per-thread setup and this method will sort that
-		out. It is also necessary to call unregisterThread before the thread shuts down.
-		@note
-		This method takes no parameters - it must be called from the thread being
-		registered and that context is enough.
-		*/
-		virtual void registerThread() = 0;
-
-		/** Unregister an additional thread which may make calls to rendersystem-related objects.
-		@see RenderSystem::registerThread
-		*/
-		virtual void unregisterThread() = 0;
-
-		/**
-		* Gets the number of display monitors.
-		@see Root::getDisplayMonitorCount
-		*/
-		virtual unsigned int getDisplayMonitorCount() const = 0;
 		/************************************************************************/
 		/* 							INTERNAL CALLBACKS                     		*/
 		/************************************************************************/
 	protected:
-		virtual void startUp_internal(AsyncOp& asyncOp);
+		virtual void startUp_internal();
 
 		virtual void createRenderWindow_internal(const String &name, unsigned int width, unsigned int height, 
 			bool fullScreen, const NameValuePairList& miscParams, AsyncOp& asyncOp) = 0;
+
+		virtual void bindGpuProgram_internal(GpuProgramRef prg);
+
+		virtual void unbindGpuProgram_internal(GpuProgramType gptype);
+
+		virtual void bindGpuProgramParameters_internal(GpuProgramType gptype, 
+			GpuProgramParametersSharedPtr params, UINT16 variabilityMask) = 0;
+		/************************************************************************/
+		/* 						INTERNAL DATA & METHODS                      	*/
+		/************************************************************************/
 	protected:
 		/** The render targets. */
 		RenderTargetMap mRenderTargets;
@@ -970,10 +925,6 @@ namespace CamelotEngine
 		bool mVSync;
 		unsigned int mVSyncInterval;
 
-		size_t mBatchCount;
-		size_t mFaceCount;
-		size_t mVertexCount;
-
 		bool mInvertVertexWinding;
 
 		/// Texture units from this upwards are disabled
@@ -989,13 +940,14 @@ namespace CamelotEngine
 		bool mClipPlanesDirty;
 
 		/// Used to store the capabilities of the graphics card
-		RenderSystemCapabilities* mRealCapabilities;
 		RenderSystemCapabilities* mCurrentCapabilities;
-		bool mUseCustomCapabilities;
 
 		/// Internal method used to set the underlying clip planes when needed
 		virtual void setClipPlanesImpl(const PlaneList& clipPlanes) = 0;
 
+		/** Query the real capabilities of the GPU and driver in the RenderSystem*/
+		virtual RenderSystemCapabilities* createRenderSystemCapabilities() const = 0;
+
 		/** Initialize the render system from the capabilities*/
 		virtual void initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary) = 0;
 
@@ -1026,12 +978,16 @@ namespace CamelotEngine
 		CM_MUTEX(mRSContextMutex)
 		CM_MUTEX(mRSRenderCallbackMutex)
 		CM_MUTEX(mResourceContextMutex)
+		CM_MUTEX(mActiveContextMutex)
 
 #if CM_THREAD_SUPPORT
 		CM_THREAD_TYPE* mRenderThread;
 #endif
 
-		RenderSystemContextPtr mResourceContext;
+		mutable RenderSystemContextPtr mResourceContext;
+		RenderSystemContextPtr mPrimaryContext;
+		mutable RenderSystemContextPtr mActiveContext;
+
 		vector<RenderSystemContextPtr>::type mRenderSystemContexts;
 		boost::signal<void()> PreRenderThreadUpdateCallback;
 		boost::signal<void()> PostRenderThreadUpdateCallback;
@@ -1067,6 +1023,13 @@ namespace CamelotEngine
 		 */
 		void submitToGpu(RenderSystemContextPtr context, bool blockUntilComplete);
 
+		/**
+		 * @brief	Sets an active context on which all subsequent RenderSystem calls will be executed on.
+		 * 			
+		 * @note	context must not be null.
+		 */
+		void setActiveContext(RenderSystemContextPtr context);
+
 	public:
 		/**
 		 * @brief	Returns the id of the render thread. If a separate render thread

+ 41 - 8
CamelotRenderer/Include/CmRenderSystemContext.h

@@ -17,12 +17,19 @@ namespace CamelotEngine
 	private:
 		struct RenderSystemCommand
 		{
-			RenderSystemCommand(boost::function<void(AsyncOp&)> _callback)
-				:callback(_callback)
+			RenderSystemCommand(boost::function<void(AsyncOp&)> _callback, UINT32 _callbackId = 0)
+				:callbackWithReturnValue(_callback), returnsValue(true), callbackId(_callbackId)
 			{ }
 
-			boost::function<void(AsyncOp&)> callback;
+			RenderSystemCommand(boost::function<void()> _callback, UINT32 _callbackId = 0)
+				:callback(_callback), returnsValue(false), callbackId(_callbackId)
+			{ }
+
+			boost::function<void()> callback;
+			boost::function<void(AsyncOp&)> callbackWithReturnValue;
 			AsyncOp asyncOp;
+			bool returnsValue;
+			UINT32 callbackId;
 		};
 
 		/************************************************************************/
@@ -51,15 +58,29 @@ namespace CamelotEngine
 		 * 			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
+		 * 			@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).
+		 * @param	_callbackId			   	(optional) Identifier for the callback so you can then later find it
+		 * 									if needed.
+		 *
+		 * @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 queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, UINT32 _callbackId = 0);
+
+		/**
+		 * @brief	Queue up a new command to execute. Make sure the provided function has all of its
+		 * 			parameters properly bound. Provided command is not expected to return a value.
+		 * 			If you wish to return a value from the callback use the other overload of queueCommand 
+		 * 			which accepts AsyncOp parameter.
+		 *
+		 * @param	_callbackId			   	(optional) Identifier for the callback so you can then later find it
+		 * 									if needed.
 		 */
-		AsyncOp queueCommand(boost::function<void(AsyncOp&)> commandCallback);
+		void queueCommand(boost::function<void()> commandCallback, UINT32 _callbackId = 0);
 
 		/**
 		 * @brief	Plays all queued commands. Should only be called from the render thread,
@@ -88,5 +109,17 @@ namespace CamelotEngine
 		 * 			it will cause a deadlock since processing will never be completed. 
 		 */
 		void blockUntilExecuted();
+
+		/************************************************************************/
+		/* 								STATES		                     		*/
+		/* These are various states we cache per RenderSystemContext. They are  */
+		/* used as a quick way of accessing the current state. If we didn't keep*/
+		/* these, then whenever user wanted to know a certain state we would    */
+		/* have to go and execute all commands to find what it is.				*/
+		/************************************************************************/
+
+		// TODO - This is actually a clumsy way of keeping state. Better and more generic way would be to
+		// search through all commands for a specific state change and find what it is.
+		bool waitForVerticalBlank;
 	};
 }

+ 110 - 128
CamelotRenderer/Source/CmRenderSystem.cpp

@@ -60,9 +60,7 @@ namespace CamelotEngine {
 		, mGeometryProgramBound(false)
         , mFragmentProgramBound(false)
 		, mClipPlanesDirty(true)
-		, mRealCapabilities(0)
-		, mCurrentCapabilities(0)
-		, mUseCustomCapabilities(false)
+		, mCurrentCapabilities(nullptr)
 		, mRenderThreadFunc(nullptr)
 		, mRenderThreadShutdown(false)
     {
@@ -72,13 +70,34 @@ namespace CamelotEngine {
     RenderSystem::~RenderSystem()
     {
         shutdown();
-		delete mRealCapabilities;
-		mRealCapabilities = 0;
-		// Current capabilities managed externally
+
+		delete mCurrentCapabilities;
 		mCurrentCapabilities = 0;
     }
+	//-----------------------------------------------------------------------
+	void RenderSystem::startUp()
+	{
+		mRenderThreadId = CM_THREAD_CURRENT_ID;
+		mResourceContext = createRenderSystemContext();
+		mPrimaryContext = createRenderSystemContext();
+		mActiveContext = mPrimaryContext;
+
+		initRenderThread(); // TODO - Move render thread to the outside of the RS
+
+		{
+			CM_LOCK_MUTEX(mResourceContextMutex)
+				mResourceContext->queueCommand(boost::bind(&RenderSystem::startUp_internal, this));
+		}
+	}
+	//-----------------------------------------------------------------------
+	void RenderSystem::swapAllRenderTargetBuffers(bool waitForVSync)
+	{
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+		mActiveContext->queueCommand(boost::bind(&RenderSystem::swapAllRenderTargetBuffers_internal, this, waitForVSync));
+	}
     //-----------------------------------------------------------------------
-    void RenderSystem::swapAllRenderTargetBuffers(bool waitForVSync)
+    void RenderSystem::swapAllRenderTargetBuffers_internal(bool waitForVSync)
     {
         // Update all in order of priority
         // This ensures render-to-texture targets get updated before render windows
@@ -89,19 +108,6 @@ namespace CamelotEngine {
 			if( itarg->second->isActive())
 				itarg->second->swapBuffers(waitForVSync);
 		}
-    }
-    //-----------------------------------------------------------------------
-    void RenderSystem::startUp()
-    {
-		mRenderThreadId = CM_THREAD_CURRENT_ID;
-		mResourceContext = 	createRenderSystemContext();
-
-		initRenderThread(); // TODO - Move render thread to the outside of the RS
-
-		{
-			CM_LOCK_MUTEX(mResourceContextMutex)
-			mResourceContext->queueCommand(boost::bind(&RenderSystem::startUp_internal, this, _1));
-		}
     }
 	//---------------------------------------------------------------------------------------------
 	RenderWindow* RenderSystem::createRenderWindow(const String &name, unsigned int width, unsigned int height, 
@@ -112,26 +118,14 @@ namespace CamelotEngine {
 			CM_LOCK_MUTEX(mResourceContextMutex)
 
 			if(miscParams != nullptr)
-				op = mResourceContext->queueCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, *miscParams, _1));
+				op = mResourceContext->queueReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, *miscParams, _1));
 			else
-				op = mResourceContext->queueCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, NameValuePairList(), _1));
+				op = mResourceContext->queueReturnCommand(boost::bind(&RenderSystem::createRenderWindow_internal, this, name, width, height, fullScreen, NameValuePairList(), _1));
 		}
 
 		submitToGpu(mResourceContext, true);
 		return op.getReturnValue<RenderWindow*>();
 	}
-	//---------------------------------------------------------------------------------------------
-	void RenderSystem::useCustomRenderSystemCapabilities(RenderSystemCapabilities* capabilities)
-	{
-		if (mRealCapabilities != 0)
-		{
-			CM_EXCEPT(InternalErrorException, 
-				"Custom render capabilities must be set before the RenderSystem is initialised.");
-		}
-
-		mCurrentCapabilities = capabilities;
-		mUseCustomCapabilities = true;
-	}
     //---------------------------------------------------------------------------------------------
     void RenderSystem::destroyRenderWindow(const String& name)
     {
@@ -287,21 +281,25 @@ namespace CamelotEngine {
         setTextureFiltering(unit, FT_MAG, magFilter);
         setTextureFiltering(unit, FT_MIP, mipFilter);
     }
-    //-----------------------------------------------------------------------
-    CullingMode RenderSystem::getCullingMode(void) const
-    {
-        return mCullingMode;
-    }
-    //-----------------------------------------------------------------------
-    bool RenderSystem::getWaitForVerticalBlank(void) const
-    {
-        return mVSync;
-    }
-    //-----------------------------------------------------------------------
-    void RenderSystem::setWaitForVerticalBlank(bool enabled)
-    {
-        mVSync = enabled;
-    }
+	//-----------------------------------------------------------------------
+	CullingMode RenderSystem::getCullingMode(void) const
+	{
+		return mCullingMode;
+	}
+	//-----------------------------------------------------------------------
+	bool RenderSystem::getWaitForVerticalBlank(void) const
+	{
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+		return mActiveContext->waitForVerticalBlank;
+	}
+	//-----------------------------------------------------------------------
+	void RenderSystem::setWaitForVerticalBlank(bool enabled)
+	{
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+		mActiveContext->waitForVerticalBlank = enabled;
+	}
     //-----------------------------------------------------------------------
     void RenderSystem::shutdown(void)
     {
@@ -322,27 +320,6 @@ namespace CamelotEngine {
 
 		shutdownRenderThread();
     }
-    //-----------------------------------------------------------------------
-    void RenderSystem::beginGeometryCount(void)
-    {
-        mBatchCount = mFaceCount = mVertexCount = 0;
-
-    }
-    //-----------------------------------------------------------------------
-    unsigned int RenderSystem::getFaceCount(void) const
-    {
-        return static_cast< unsigned int >( mFaceCount );
-    }
-    //-----------------------------------------------------------------------
-    unsigned int RenderSystem::getBatchCount(void) const
-    {
-        return static_cast< unsigned int >( mBatchCount );
-    }
-    //-----------------------------------------------------------------------
-    unsigned int RenderSystem::getVertexCount(void) const
-    {
-        return static_cast< unsigned int >( mVertexCount );
-    }
     //-----------------------------------------------------------------------
 	void RenderSystem::convertColorValue(const Color& colour, UINT32* pDest)
 	{
@@ -352,32 +329,6 @@ namespace CamelotEngine {
     //-----------------------------------------------------------------------
     void RenderSystem::render(const RenderOperation& op)
     {
-        // Update stats
-        size_t val;
-
-        if (op.useIndexes)
-            val = op.indexData->indexCount;
-        else
-            val = op.vertexData->vertexCount;
-
-        switch(op.operationType)
-        {
-		case RenderOperation::OT_TRIANGLE_LIST:
-            mFaceCount += val / 3;
-            break;
-        case RenderOperation::OT_TRIANGLE_STRIP:
-        case RenderOperation::OT_TRIANGLE_FAN:
-            mFaceCount += val - 2;
-            break;
-	    case RenderOperation::OT_POINT_LIST:
-	    case RenderOperation::OT_LINE_LIST:
-	    case RenderOperation::OT_LINE_STRIP:
-	        break;
-	    }
-
-        mVertexCount += op.vertexData->vertexCount;
-        mBatchCount += 1;
-
 		// sort out clip planes
 		// have to do it here in case of matrix issues
 		if (mClipPlanesDirty)
@@ -428,41 +379,26 @@ namespace CamelotEngine {
 	//-----------------------------------------------------------------------
 	void RenderSystem::bindGpuProgram(GpuProgramRef prg)
 	{
-	    switch(prg->_getBindingDelegate()->getType())
-	    {
-        case GPT_VERTEX_PROGRAM:
-			// mark clip planes dirty if changed (programmable can change space)
-			if (!mVertexProgramBound && !mClipPlanes.empty())
-				mClipPlanesDirty = true;
+		CM_LOCK_MUTEX(mActiveContextMutex);
 
-            mVertexProgramBound = true;
-	        break;
-        case GPT_GEOMETRY_PROGRAM:
-			mGeometryProgramBound = true;
-			break;
-        case GPT_FRAGMENT_PROGRAM:
-            mFragmentProgramBound = true;
-	        break;
-	    }
+		mActiveContext->queueCommand(boost::bind(&RenderSystem::bindGpuProgram_internal, this, prg));
 	}
 	//-----------------------------------------------------------------------
 	void RenderSystem::unbindGpuProgram(GpuProgramType gptype)
 	{
-	    switch(gptype)
-	    {
-        case GPT_VERTEX_PROGRAM:
-			// mark clip planes dirty if changed (programmable can change space)
-			if (mVertexProgramBound && !mClipPlanes.empty())
-				mClipPlanesDirty = true;
-            mVertexProgramBound = false;
-	        break;
-        case GPT_GEOMETRY_PROGRAM:
-			mGeometryProgramBound = false;
-			break;
-        case GPT_FRAGMENT_PROGRAM:
-            mFragmentProgramBound = false;
-	        break;
-	    }
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+	    mActiveContext->queueCommand(boost::bind(&RenderSystem::unbindGpuProgram_internal, this, gptype));
+	}
+	//-----------------------------------------------------------------------
+	void RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 
+		GpuProgramParametersSharedPtr params, UINT16 variabilityMask)
+	{
+		GpuProgramParametersSharedPtr paramCopy = GpuProgramParametersSharedPtr(new GpuProgramParameters(*params));
+
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+		mActiveContext->queueCommand(boost::bind(&RenderSystem::bindGpuProgramParameters_internal, this, gptype, paramCopy, variabilityMask));
 	}
 	//-----------------------------------------------------------------------
 	bool RenderSystem::isGpuProgramBound(GpuProgramType gptype)
@@ -616,6 +552,15 @@ namespace CamelotEngine {
 			context->blockUntilExecuted();
 	}
 
+	void RenderSystem::setActiveContext(RenderSystemContextPtr context)
+	{
+		assert(context != nullptr);
+
+		CM_LOCK_MUTEX(mActiveContextMutex);
+
+		mActiveContext = context;
+	}
+
 	void RenderSystem::update()
 	{
 		{
@@ -640,13 +585,50 @@ namespace CamelotEngine {
 	/* 							INTERNAL CALLBACKS                     		*/
 	/************************************************************************/
 
-	void RenderSystem::startUp_internal(AsyncOp& asyncOp)
+	void RenderSystem::startUp_internal()
 	{
 		mVertexProgramBound = false;
 		mGeometryProgramBound = false;
 		mFragmentProgramBound = false;
+	}
 
-		asyncOp.completeOperation();
+	void RenderSystem::bindGpuProgram_internal(GpuProgramRef prg)
+	{
+		switch(prg->_getBindingDelegate()->getType())
+		{
+		case GPT_VERTEX_PROGRAM:
+			// mark clip planes dirty if changed (programmable can change space)
+			if (!mVertexProgramBound && !mClipPlanes.empty())
+				mClipPlanesDirty = true;
+
+			mVertexProgramBound = true;
+			break;
+		case GPT_GEOMETRY_PROGRAM:
+			mGeometryProgramBound = true;
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			mFragmentProgramBound = true;
+			break;
+		}
+	}
+
+	void RenderSystem::unbindGpuProgram_internal(GpuProgramType gptype)
+	{
+		switch(gptype)
+		{
+		case GPT_VERTEX_PROGRAM:
+			// mark clip planes dirty if changed (programmable can change space)
+			if (mVertexProgramBound && !mClipPlanes.empty())
+				mClipPlanesDirty = true;
+			mVertexProgramBound = false;
+			break;
+		case GPT_GEOMETRY_PROGRAM:
+			mGeometryProgramBound = false;
+			break;
+		case GPT_FRAGMENT_PROGRAM:
+			mFragmentProgramBound = false;
+			break;
+		}
 	}
 
 	/************************************************************************/

+ 32 - 6
CamelotRenderer/Source/CmRenderSystemContext.cpp

@@ -8,11 +8,12 @@ namespace CamelotEngine
 {
 	RenderSystemContext::RenderSystemContext(CM_THREAD_ID_TYPE threadId)
 		:mMyThreadId(threadId), mReadyCommands(nullptr), mIsExecuting(false)
+		, waitForVerticalBlank(true)
 	{
 		mCommands = new vector<RenderSystemCommand>::type();
 	}
 
-	AsyncOp RenderSystemContext::queueCommand(boost::function<void(AsyncOp&)> commandCallback)
+	AsyncOp RenderSystemContext::queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, UINT32 _callbackId)
 	{
 #if CM_DEBUG_MODE
 #if CM_THREAD_SUPPORT != 0
@@ -23,12 +24,27 @@ namespace CamelotEngine
 #endif
 #endif
 
-		RenderSystemCommand newCommand(commandCallback);
+		RenderSystemCommand newCommand(commandCallback, _callbackId);
 		mCommands->push_back(newCommand);
 
 		return newCommand.asyncOp;
 	}
 
+	void RenderSystemContext::queueCommand(boost::function<void()> commandCallback, UINT32 _callbackId)
+	{
+#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, _callbackId);
+		mCommands->push_back(newCommand);
+	}
+
 	void RenderSystemContext::submitToGpu()
 	{
 		{
@@ -76,12 +92,22 @@ namespace CamelotEngine
 
 		for(auto iter = currentCommands->begin(); iter != currentCommands->end(); ++iter)
 		{
-			(*iter).callback((*iter).asyncOp);
+			RenderSystemCommand command = (*iter);
 
-			if(!(*iter).asyncOp.hasCompleted())
+			if(command.returnsValue)
+			{
+				command.callbackWithReturnValue(command.asyncOp);
+
+				if(!command.asyncOp.hasCompleted())
+				{
+					LOGDBG("Async operation return value wasn't resolved properly. Resolving automatically to nullptr. " \
+						 "Make sure to complete the operation before returning from the command callback method.");
+					command.asyncOp.completeOperation(nullptr);
+				}
+			}
+			else
 			{
-				LOGDBG("Async operation wasn't resolved properly. Resolving automatically to nullptr.");
-				(*iter).asyncOp.completeOperation(nullptr);
+				command.callback();
 			}
 		}
 

+ 2 - 0
CamelotRenderer/TODO.txt

@@ -17,6 +17,7 @@ High-level TODO:
 
 Command buffer TODO:
  Immediate:
+  - Resource updates shouldn't happen once per frame. Resources should be submitted to render thread immediately.
   - Port the rest of the RenderSystem of use RenderContext
   - Port resource creation to use RenderContext (texture/mesh/shader/etc initialization and updates)
   - Make sure to add thread checks (surrounded by #if DEBUG) to RenderSystem and Vertex/Index/Pixel buffers, textures, meshes, etc.
@@ -27,6 +28,7 @@ Command buffer TODO:
   - Provide Async versions of all read commands
   - Add documentation that tells the user that reading a resource non-async will block the thread and execute all queued render commands first
   - Add documentation that tells the user that resource updates only get applied at the end of the frame, unless you manually override it.
+  - Create render thread in Application, and not in RenderSystem?
 
 HIGH PRIORITY TODO:
  - Issue with deserialization and value types: