Pārlūkot izejas kodu

More multithreaded changes, mostly to GpuPrograms

Marko Pintera 13 gadi atpakaļ
vecāks
revīzija
d87a5e8fc4
42 mainītis faili ar 215 papildinājumiem un 90 dzēšanām
  1. 0 2
      CamelotClient/CamelotClient.cpp
  2. 2 2
      CamelotD3D9Renderer/Include/CmD3D9GpuProgram.h
  3. 1 1
      CamelotD3D9Renderer/Include/CmD3D9HLSLProgramRTTI.h
  4. 7 5
      CamelotD3D9Renderer/Source/CmD3D9GpuProgram.cpp
  5. 1 1
      CamelotD3D9Renderer/Source/CmD3D9RenderSystem.cpp
  6. 3 1
      CamelotD3D9Renderer/Source/CmD3D9Texture.cpp
  7. 2 2
      CamelotForwardRenderer/Source/CmForwardRenderer.cpp
  8. 1 1
      CamelotGLRenderer/Include/CmGLSLProgramRTTI.h
  9. 1 1
      CamelotGLRenderer/Source/CmGLRenderSystem.cpp
  10. 2 1
      CamelotGLRenderer/Source/CmGLTexture.cpp
  11. 1 1
      CamelotGLRenderer/Source/GLSL/include/CmGLSLGpuProgram.h
  12. 2 1
      CamelotGLRenderer/Source/GLSL/src/CmGLSLGpuProgram.cpp
  13. 1 0
      CamelotRenderer/CamelotRenderer.vcxproj
  14. 1 0
      CamelotRenderer/CamelotRenderer.vcxproj.filters
  15. 1 1
      CamelotRenderer/Include/CmCgProgramRTTI.h
  16. 13 2
      CamelotRenderer/Include/CmGpuProgram.h
  17. 6 0
      CamelotRenderer/Include/CmGpuProgramRTTI.h
  18. 15 2
      CamelotRenderer/Include/CmHighLevelGpuProgram.h
  19. 9 4
      CamelotRenderer/Include/CmHighLevelGpuProgramManager.h
  20. 1 1
      CamelotRenderer/Include/CmMaterial.h
  21. 1 1
      CamelotRenderer/Include/CmMesh.h
  22. 19 4
      CamelotRenderer/Include/CmResource.h
  23. 7 7
      CamelotRenderer/Include/CmResourceHandle.h
  24. 1 1
      CamelotRenderer/Include/CmShader.h
  25. 7 2
      CamelotRenderer/Include/CmTexture.h
  26. 7 0
      CamelotRenderer/Include/CmTextureManager.h
  27. 11 9
      CamelotRenderer/Include/CmTextureRTTI.h
  28. 1 1
      CamelotRenderer/Source/CmCgProgram.cpp
  29. 8 2
      CamelotRenderer/Source/CmGpuProgram.cpp
  30. 1 1
      CamelotRenderer/Source/CmGpuProgramManager.cpp
  31. 11 2
      CamelotRenderer/Source/CmHighLevelGpuProgram.cpp
  32. 9 0
      CamelotRenderer/Source/CmHighLevelGpuProgramManager.cpp
  33. 0 1
      CamelotRenderer/Source/CmImporter.cpp
  34. 1 1
      CamelotRenderer/Source/CmMesh.cpp
  35. 4 1
      CamelotRenderer/Source/CmRenderSystem.cpp
  36. 3 8
      CamelotRenderer/Source/CmResource.cpp
  37. 6 1
      CamelotRenderer/Source/CmResourceHandle.cpp
  38. 3 1
      CamelotRenderer/Source/CmResources.cpp
  39. 1 1
      CamelotRenderer/Source/CmShader.cpp
  40. 7 0
      CamelotRenderer/Source/CmTextureManager.cpp
  41. 30 17
      CamelotRenderer/TODO.txt
  42. 7 0
      TODODoc.txt

+ 0 - 2
CamelotClient/CamelotClient.cpp

@@ -86,7 +86,6 @@ int _tmain(int argc, _TCHAR* argv[])
 							}";
 
 	fragProg =  HighLevelGpuProgram::create(fragShaderCode, "ps_main", "cg", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
-	fragProg->init();
 
 	String vertShaderCode = "float4x4 matViewProjection;	\
 							void vs_main(										\
@@ -100,7 +99,6 @@ int _tmain(int argc, _TCHAR* argv[])
 							}";
 
 	vertProg =  HighLevelGpuProgram::create(vertShaderCode, "vs_main", "cg", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
-	vertProg->init();
 
 	HighLevelGpuProgramHandle vertProgRef(vertProg);
 

+ 2 - 2
CamelotD3D9Renderer/Include/CmD3D9GpuProgram.h

@@ -42,9 +42,9 @@ namespace CamelotEngine {
         D3D9GpuProgram();
         ~D3D9GpuProgram();
 
-		virtual void initImpl(void);
+		virtual void initialize_internal(void);
 		/** Loads this program to specified device */
-		virtual void initImpl(IDirect3DDevice9* d3d9Device);
+		virtual void initialize_internal(IDirect3DDevice9* d3d9Device);
 		/** Overridden from GpuProgram */
 		virtual void unload(void);
 

+ 1 - 1
CamelotD3D9Renderer/Include/CmD3D9HLSLProgramRTTI.h

@@ -27,7 +27,7 @@ namespace CamelotEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
 		{
-			return HighLevelGpuProgramManager::instance().create("hlsl");
+			return HighLevelGpuProgramManager::instance().createEmpty("hlsl");
 		}
 	};
 }

+ 7 - 5
CamelotD3D9Renderer/Source/CmD3D9GpuProgram.cpp

@@ -73,7 +73,7 @@ namespace CamelotEngine {
 	}
 
 	//-----------------------------------------------------------------------------
-    void D3D9GpuProgram::initImpl(void)
+    void D3D9GpuProgram::initialize_internal(void)
     {
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
@@ -81,12 +81,14 @@ namespace CamelotEngine {
 		{
 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
 
-			initImpl(d3d9Device);
+			initialize_internal(d3d9Device);
 		}		       
+
+		Resource::initialize_internal();
     }
 
 	//-----------------------------------------------------------------------------
-	void D3D9GpuProgram::initImpl(IDirect3DDevice9* d3d9Device)
+	void D3D9GpuProgram::initialize_internal(IDirect3DDevice9* d3d9Device)
 	{
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
@@ -263,7 +265,7 @@ namespace CamelotEngine {
 		// Shader was not found -> load it.
 		if (it == mMapDeviceToVertexShader.end())		
 		{
-			initImpl(d3d9Device);		
+			initialize_internal(d3d9Device);		
 			it = mMapDeviceToVertexShader.find(d3d9Device);
 		}
 	
@@ -366,7 +368,7 @@ namespace CamelotEngine {
 		// Shader was not found -> load it.
 		if (it == mMapDeviceToPixelShader.end())		
 		{
-			initImpl(d3d9Device);			
+			initialize_internal(d3d9Device);			
 			it = mMapDeviceToPixelShader.find(d3d9Device);
 		}
 

+ 1 - 1
CamelotD3D9Renderer/Source/CmD3D9RenderSystem.cpp

@@ -273,7 +273,7 @@ namespace CamelotEngine
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 
-		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+		GpuProgram* bindingPrg = prg->getBindingDelegate_internal();
 
 		HRESULT hr;
 		switch (bindingPrg->getType())

+ 3 - 1
CamelotD3D9Renderer/Source/CmD3D9Texture.cpp

@@ -215,7 +215,9 @@ namespace CamelotEngine
 				createInternalResourcesImpl(d3d9Device);
 				return;
 			}	
-		}		
+		}	
+
+		Resource::initialize_internal();
 	}
 	/****************************************************************************************/
 	void D3D9Texture::freeInternalResources(void)

+ 2 - 2
CamelotForwardRenderer/Source/CmForwardRenderer.cpp

@@ -63,12 +63,12 @@ namespace CamelotEngine
 		{
 			MaterialHandle material = (*iter)->getMaterial();
 
-			if(material == nullptr || !material.isResolved())
+			if(material == nullptr || !material.isLoaded())
 				continue;
 
 			MeshHandle mesh = (*iter)->getMesh();
 
-			if(mesh == nullptr || !mesh.isResolved())
+			if(mesh == nullptr || !mesh.isLoaded())
 				continue;
 
 			// TODO - Renderer should ensure shader is compatible with it, and it contains all the needed parameters

+ 1 - 1
CamelotGLRenderer/Include/CmGLSLProgramRTTI.h

@@ -27,7 +27,7 @@ namespace CamelotEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
 		{
-			return HighLevelGpuProgramManager::instance().create("glsl");
+			return HighLevelGpuProgramManager::instance().createEmpty("glsl");
 		}
 	};
 }

+ 1 - 1
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -258,7 +258,7 @@ namespace CamelotEngine {
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 
-		GpuProgram* bindingPrg = prg->_getBindingDelegate();
+		GpuProgram* bindingPrg = prg->getBindingDelegate_internal();
 		GLGpuProgram* glprg = static_cast<GLGpuProgram*>(bindingPrg);
 
 		// Unbind previous gpu program first.

+ 2 - 1
CamelotGLRenderer/Source/CmGLTexture.cpp

@@ -78,8 +78,9 @@ namespace CamelotEngine {
 		if( mUsage & TU_RENDERTARGET )
 		{
 			createRenderTexture();
-			return;
 		}
+
+		Resource::initialize_internal();
 	}
 
     GLenum GLTexture::getGLTextureTarget_internal(void) const

+ 1 - 1
CamelotGLRenderer/Source/GLSL/include/CmGLSLGpuProgram.h

@@ -90,7 +90,7 @@ namespace CamelotEngine {
 		/// @copydoc Resource::unloadImpl
 		void unloadImpl(void);
 		/// @copydoc Resource::loadImpl
-		void initImpl(void);
+		void initialize_internal(void);
 
 
     };

+ 2 - 1
CamelotGLRenderer/Source/GLSL/src/CmGLSLGpuProgram.cpp

@@ -66,8 +66,9 @@ namespace CamelotEngine {
         unload(); 
     }
 	//-----------------------------------------------------------------------------
-    void GLSLGpuProgram::initImpl(void)
+    void GLSLGpuProgram::initialize_internal(void)
     {
+		Resource::initialize_internal();
 		// nothing to load
     }
 

+ 1 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -90,6 +90,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <Text Include="..\TODODoc.txt" />
     <Text Include="HighLevelTODO.txt" />
     <Text Include="TODO.txt" />
   </ItemGroup>

+ 1 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -86,6 +86,7 @@
   <ItemGroup>
     <Text Include="TODO.txt" />
     <Text Include="HighLevelTODO.txt" />
+    <Text Include="..\TODODoc.txt" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\CmConfigOptionMap.h">

+ 1 - 1
CamelotRenderer/Include/CmCgProgramRTTI.h

@@ -27,7 +27,7 @@ namespace CamelotEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
 		{
-			return HighLevelGpuProgramManager::instance().create("cg");
+			return HighLevelGpuProgramManager::instance().createEmpty("cg");
 		}
 	};
 }

+ 13 - 2
CamelotRenderer/Include/CmGpuProgram.h

@@ -118,7 +118,18 @@ namespace CamelotEngine {
 
 		virtual ~GpuProgram() {}
 
-		virtual void initImpl();
+		/**
+		 * @brief	Initializes the gpu program. This must be called right after the program is constructed. 
+		 * 			Called by GpuProgramManager upon creation, so usually you don't want to call this manually. 
+		 * 			
+		 * @note	Initialization is not done immediately, and is instead just scheduled on the render thread.
+		 */
+		void initialize();
+
+		/**
+		 * @brief	Performs GpuProgram initialization. Only callable from the render thread.
+		 */
+		virtual void initialize_internal();
 		virtual void unload() {}
 
 		/** Sets the source assembly for this program from an in-memory string.
@@ -150,7 +161,7 @@ namespace CamelotEngine {
         @remarks
             This method is simply to allow some subclasses of GpuProgram to delegate
             the program which is bound to the pipeline to a delegate, if required. */
-        virtual GpuProgram* _getBindingDelegate(void) { return this; }
+        virtual GpuProgram* getBindingDelegate_internal(void) { return this; }
 
         /** Returns whether this program can be supported on the current renderer and hardware. */
         virtual bool isSupported(void) const;

+ 6 - 0
CamelotRenderer/Include/CmGpuProgramRTTI.h

@@ -33,6 +33,12 @@ namespace CamelotEngine
 			CM_ADD_PLAINFIELD(mSyntaxCode, 7, GpuProgramRTTI)
 		}
 
+		virtual void onDeserializationEnded(IReflectable* obj)
+		{
+			GpuProgram* gpuProgram = static_cast<GpuProgram*>(obj);
+			gpuProgram->initialize();
+		}
+
 		virtual const String& getRTTIName()
 		{
 			static String name = "GpuProgram";

+ 15 - 2
CamelotRenderer/Include/CmHighLevelGpuProgram.h

@@ -98,7 +98,19 @@ namespace CamelotEngine {
         HighLevelGpuProgram();
         ~HighLevelGpuProgram();
 
-		virtual void initImpl();
+		/**
+		 * @brief	Initializes the gpu program. This must be called right after the program is constructed. 
+		 * 			Called by HighLevelGpuManager upon creation, so usually you don't want to call this manually.
+		 * 			
+		 * @note	Initialization is not done immediately, and is instead just scheduled on the render thread.
+		 */
+		void initialize();
+
+		/**
+		 * @brief	Performs HighLevelGpuProgram initialization. Only callable from the render thread.
+		 */
+		virtual void initialize_internal();
+
 		virtual void unload();
 
         /** Creates a new parameters object compatible with this program definition. 
@@ -109,8 +121,9 @@ namespace CamelotEngine {
             object containing the definition of the parameters this program understands.
         */
         GpuProgramParametersSharedPtr createParameters(void);
+
         /** @copydoc GpuProgram::getBindingDelegate */
-        GpuProgram* _getBindingDelegate(void) { return mAssemblerProgram.get(); }
+        GpuProgram* getBindingDelegate_internal(void) { return mAssemblerProgram.get(); }
 
 		/** Get the full list of GpuConstantDefinition instances.
 		@note

+ 9 - 4
CamelotRenderer/Include/CmHighLevelGpuProgramManager.h

@@ -90,11 +90,9 @@ namespace CamelotEngine {
 		bool isLanguageSupported(const String& lang);
 
 
-        /** Create a new, unloaded HighLevelGpuProgram. 
+        /** Create a new HighLevelGpuProgram. 
 		@par
 			This method creates a new program of the type specified as the second and third parameters.
-			You will have to call further methods on the returned program in order to 
-			define the program fully before you can load it.
 		@param name The identifying name of the program
         @param groupName The name of the resource group which this program is
             to be a member of
@@ -103,13 +101,20 @@ namespace CamelotEngine {
 		*/
 		HighLevelGpuProgramPtr create(const String& source, const String& entryPoint, const String& language, GpuProgramType gptype, GpuProgramProfile profile);
 
-		/** Create a new, unloaded HighLevelGpuProgram. 
+		/** Create a new HighLevelGpuProgram. 
 		@par
 			This method creates a new program of the specified language. You need to set other 
 			properties like source, entry point, type, profile manually.
 		@param language Code of the language to use (e.g. "cg")
 		*/
 		HighLevelGpuProgramPtr create(const String& language);
+
+		/**
+		 * @brief	Creates a completely empty and uninitialized HighLevelGpuProgram.
+		 * 			Should only be used for VERY specific purposes, like deserialization,
+		 * 			as it requires additional manual initialization that is not required normally.
+		 */
+		HighLevelGpuProgramPtr createEmpty(const String& language);
 	};
 	/** @} */
 	/** @} */

+ 1 - 1
CamelotRenderer/Include/CmMaterial.h

@@ -21,7 +21,7 @@ namespace CamelotEngine
 		/**
 		 * @brief	Overridden from Resource.
 		 */
-		virtual void initImpl() { }
+		virtual void initialize_internal() { }
 
 		/**
 		 * @brief	Sets a shader that will be used by the material. 

+ 1 - 1
CamelotRenderer/Include/CmMesh.h

@@ -40,7 +40,7 @@ namespace CamelotEngine
 
 		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
 
-		virtual void initImpl();
+		virtual void initialize_internal();
 
 	private:
 		MeshDataPtr mMeshData;

+ 19 - 4
CamelotRenderer/Include/CmResource.h

@@ -14,23 +14,38 @@ namespace CamelotEngine
 		Resource();
 		virtual ~Resource() {};
 
-		void init();
-		virtual void initImpl() {}
-
 		const String& getUUID() const { return mUUID; }
 
+		/**
+		 * @brief	Returns true if the object has been properly initialized. You are not
+		 * 			allowed to call any methods on the resource until you are sure resource is initialized.
+		 */
+		bool isInitialized() const { return mIsInitialized; }
+
 	protected:
 		friend class Resources;
 		//virtual void unload() = 0;
 
 		//virtual void calculateSize() = 0;
 		//virtual void reload();
+		
+		/**
+		 * @brief	Finishes up resource initialization. Usually called right after the resource is created.
+		 * 			Make sure that derived classes implement their own initialize_internal, and make sure
+		 * 			they call this implementation from it.
+		 */
+		virtual void initialize_internal();
+
+		/**
+		 * @brief	Marks the resource as initialized.
+		 */
+		void setInitialized() { mIsInitialized = true; }
 
 		String mUUID; 
 		UINT32 mSize;
 
 		// Transient
-		bool mInitialized;
+		bool mIsInitialized;
 
 	/************************************************************************/
 	/* 								SERIALIZATION                      		*/

+ 7 - 7
CamelotRenderer/Include/CmResourceHandle.h

@@ -10,12 +10,12 @@ namespace CamelotEngine
 	struct CM_EXPORT ResourceHandleData : public IReflectable
 	{
 		ResourceHandleData()
-			:mIsResolved(false)
+			:mIsCreated(false)
 		{ }
 
 		std::shared_ptr<Resource> mPtr;
 		String mUUID;
-		bool mIsResolved;
+		bool mIsCreated;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -32,7 +32,7 @@ namespace CamelotEngine
 		/**
 		 * @brief	Checks if the resource is loaded
 		 */
-		bool isResolved() const { return mData->mIsResolved; }
+		bool isLoaded() const;
 
 	protected:
 		ResourceHandleBase();
@@ -50,7 +50,7 @@ namespace CamelotEngine
 	private:
 		friend class Resources;
 		/**
-		 * @brief	Sets the resolved flag to true. Should only be called
+		 * @brief	Sets the created flag to true. Should only be called
 		 * 			by Resources class after loading of the resource is fully done.
 		 */
 		void resolve(std::shared_ptr<Resource> ptr);
@@ -105,7 +105,7 @@ namespace CamelotEngine
 		// TODO Low priority - User can currently try to access these even if resource ptr is not resolved
 		T* get() const 
 		{ 
-			if(!isResolved()) 
+			if(!isLoaded()) 
 				return nullptr; 
 			
 			return static_cast<T*>(mData->mPtr.get()); 
@@ -113,7 +113,7 @@ namespace CamelotEngine
 		T* operator->() const { return get(); }
 		T& operator*() const { return *get(); }
 
-		std::shared_ptr<T> getInternalPtr() { if(!isResolved()) return nullptr; return std::static_pointer_cast<T>(mData->mPtr); }
+		std::shared_ptr<T> getInternalPtr() { if(!isLoaded()) return nullptr; return std::static_pointer_cast<T>(mData->mPtr); }
 
 		template<class _Ty>
 		struct CM_Bool_struct
@@ -125,7 +125,7 @@ namespace CamelotEngine
 		// (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
 		operator int CM_Bool_struct<T>::*() const
 		{
-			return ((isResolved() && (mData->mPtr.get() != 0)) ? &CM_Bool_struct<T>::_Member : 0);
+			return ((isLoaded() && (mData->mPtr.get() != 0)) ? &CM_Bool_struct<T>::_Member : 0);
 		}
 	};
 

+ 1 - 1
CamelotRenderer/Include/CmShader.h

@@ -22,7 +22,7 @@ namespace CamelotEngine
 		/**
 		 * @brief	Inherited from Resource.
 		 */
-		virtual void initImpl();
+		virtual void initialize_internal();
 
 		TechniquePtr addTechnique(const String& renderSystem, const String& renderer);
 		

+ 7 - 2
CamelotRenderer/Include/CmTexture.h

@@ -246,12 +246,17 @@ namespace CamelotEngine {
 		protected:
 
 		/**
-		 * @brief	Initializes the texture. This must be called right after the texture is constructed. Normally called by TextureManager
-		 * 			upon texture creation.
+		 * @brief	Initializes the texture. This must be called right after the texture is constructed. Called by TextureManager
+		 * 			upon texture creation, so usually you don't want to call this manually.
+		 * 			
+		 * @note	Initialization is not done immediately, and is instead just scheduled on the render thread.
 		 */
 		void initialize(TextureType textureType, size_t width, size_t height, size_t depth, size_t numMipmaps, 
 			PixelFormat format, int usage, bool hwGamma, UINT32 fsaa, const String& fsaaHint);
 		
+		/**
+		 * @brief	Performs GpuProgram initialization. Only callable from the render thread.
+		 */
 		virtual void initialize_internal() = 0;
 
 		/// @copydoc Resource::calculateSize

+ 7 - 0
CamelotRenderer/Include/CmTextureManager.h

@@ -162,6 +162,13 @@ namespace CamelotEngine {
 				num_mips, format, usage, hwGammaCorrection, fsaa, fsaaHint);
 		}
 
+		/**
+		 * @brief	Creates a completely empty and uninitialized Texture.
+		 * 			Should only be used for VERY specific purposes, like deserialization,
+		 * 			as it requires additional manual initialization that is not required normally.
+		 */
+		TexturePtr createEmpty();
+
 		/** Returns whether this render system can natively support the precise texture 
 			format requested with the given usage options.
 		@remarks

+ 11 - 9
CamelotRenderer/Include/CmTextureRTTI.h

@@ -37,7 +37,9 @@ namespace CamelotEngine
 
 		void setPixelData(Texture* obj, UINT32 idx, PixelDataPtr data)
 		{
-			mPixelData[idx] = data;
+			vector<PixelDataPtr>::type* pixelData = boost::any_cast<vector<PixelDataPtr>::type*>(obj->mRTTIData);
+
+			(*pixelData)[idx] = data;
 		}
 
 		UINT32 getPixelDataArraySize(Texture* obj)
@@ -86,6 +88,12 @@ namespace CamelotEngine
 			if(texture->mRTTIData.empty())
 				return;
 
+			// A bit clumsy initializing with already set values, but I feel its better than complicating things and storing the values
+			// in mRTTIData.
+			texture->initialize(texture->getTextureType(), texture->getWidth(), texture->getHeight(), texture->getDepth(), 
+				texture->getNumMipmaps(), texture->getFormat(), texture->getUsage(), texture->isHardwareGammaEnabled(), 
+				texture->getFSAA(), texture->getFSAAHint());
+
 			vector<PixelDataPtr>::type* pixelData = boost::any_cast<vector<PixelDataPtr>::type*>(texture->mRTTIData);
 			for(size_t i = 0; i < pixelData->size(); i++)
 			{
@@ -96,7 +104,7 @@ namespace CamelotEngine
 			}
 
 			delete pixelData;
-			texture->mRTTIData = nullptr;			
+			texture->mRTTIData = nullptr;	
 		}
 
 		virtual const String& getRTTIName()
@@ -112,13 +120,7 @@ namespace CamelotEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
 		{
-			// DEBUG ONLY - Remove this after I implement RTTI types for specific texture types
-			return Texture::create(TEX_TYPE_2D, 128, 128, 1, PF_A8B8G8R8);
-
-			//CM_EXCEPT(InternalErrorException, "Cannot instantiate abstract class!");
+			return TextureManager::instance().createEmpty();
 		}
-
-	private:
-		vector<PixelDataPtr>::type mPixelData;
 	};
 }

+ 1 - 1
CamelotRenderer/Source/CmCgProgram.cpp

@@ -169,7 +169,7 @@ namespace CamelotEngine {
 					HighLevelGpuProgramManager::instance().create(
 					hlslSourceFromCg, "main", "hlsl", mType, mProfile);
 
-				vp->init();
+				vp->initialize();
 
 				mAssemblerProgram = vp;
 			}

+ 8 - 2
CamelotRenderer/Source/CmGpuProgram.cpp

@@ -60,13 +60,20 @@ namespace CamelotEngine
         mSource = source;
 		mCompileError = false;
     }
+	//-----------------------------------------------------------------------------
+	void GpuProgram::initialize()
+	{
+		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&GpuProgram::initialize_internal, this));
+	}
     //-----------------------------------------------------------------------------
-    void GpuProgram::initImpl(void)
+    void GpuProgram::initialize_internal(void)
     {
         // Call polymorphic load
 		try 
 		{
 			loadFromSource();
+
+			Resource::initialize_internal();
 		}
 		catch (const Exception&)
 		{
@@ -77,7 +84,6 @@ namespace CamelotEngine
 
 			mCompileError = true;
 		}
-
     }
     //-----------------------------------------------------------------------------
     bool GpuProgram::isSupported(void) const

+ 1 - 1
CamelotRenderer/Source/CmGpuProgramManager.cpp

@@ -50,7 +50,7 @@ namespace CamelotEngine {
 		{
 			prg = createProgram( code, gptype, syntaxCode);
 		}
-        prg->init();
+        prg->initialize();
         return prg;
     }
     //---------------------------------------------------------------------------

+ 11 - 2
CamelotRenderer/Source/CmHighLevelGpuProgram.cpp

@@ -27,6 +27,8 @@ THE SOFTWARE.
 */
 #include "CmHighLevelGpuProgram.h"
 #include "CmHighLevelGpuProgramManager.h"
+#include "CmRenderSystemManager.h"
+#include "CmRenderSystem.h"
 #include "CmException.h"
 
 namespace CamelotEngine
@@ -37,8 +39,13 @@ namespace CamelotEngine
         mHighLevelLoaded(false), mAssemblerProgram(0), mConstantDefsBuilt(false)
     {
     }
+	//---------------------------------------------------------------------------
+	void HighLevelGpuProgram::initialize()
+	{
+		RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&HighLevelGpuProgram::initialize_internal, this));
+	}
     //---------------------------------------------------------------------------
-    void HighLevelGpuProgram::initImpl()
+    void HighLevelGpuProgram::initialize_internal()
     {
 		if (isSupported())
 		{
@@ -51,8 +58,10 @@ namespace CamelotEngine
 			// load constructed assembler program (if it exists)
 			if (mAssemblerProgram != nullptr && mAssemblerProgram.get() != this)
 			{
-				mAssemblerProgram->init();
+				mAssemblerProgram->initialize_internal();
 			}
+
+			Resource::initialize_internal();
 		}
     }
     //---------------------------------------------------------------------------

+ 9 - 0
CamelotRenderer/Source/CmHighLevelGpuProgramManager.cpp

@@ -152,11 +152,20 @@ namespace CamelotEngine {
         HighLevelGpuProgramPtr prg = ret;
         prg->setType(gptype);
         prg->setSyntaxCode(language);
+		ret->initialize();
 
         return prg;
     }
 	//---------------------------------------------------------------------------
 	HighLevelGpuProgramPtr HighLevelGpuProgramManager::create(const String& language)
+	{
+		HighLevelGpuProgramPtr ret = HighLevelGpuProgramPtr(getFactory(language)->create());
+		ret->initialize();
+
+		return ret;
+	}
+	//---------------------------------------------------------------------------
+	HighLevelGpuProgramPtr HighLevelGpuProgramManager::createEmpty(const String& language)
 	{
 		HighLevelGpuProgramPtr ret = HighLevelGpuProgramPtr(getFactory(language)->create());
 

+ 0 - 1
CamelotRenderer/Source/CmImporter.cpp

@@ -71,7 +71,6 @@ namespace CamelotEngine
 		}
 
 		BaseResourceHandle importedResource = importer->import(inputFilePath);
-		importedResource->init();
 
 		return importedResource;
 	}

+ 1 - 1
CamelotRenderer/Source/CmMesh.cpp

@@ -160,7 +160,7 @@ namespace CamelotEngine
 		return ro;
 	}
 
-	void Mesh::initImpl()
+	void Mesh::initialize_internal()
 	{
 		if(mMeshData == nullptr)
 		{

+ 4 - 1
CamelotRenderer/Source/CmRenderSystem.cpp

@@ -732,7 +732,7 @@ namespace CamelotEngine {
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 
-		switch(prg->_getBindingDelegate()->getType())
+		switch(prg->getBindingDelegate_internal()->getType())
 		{
 		case GPT_VERTEX_PROGRAM:
 			// mark clip planes dirty if changed (programmable can change space)
@@ -989,6 +989,9 @@ namespace CamelotEngine {
 
 	void RenderSystem::submitToGpu(RenderSystemContextPtr context, bool blockUntilComplete)
 	{
+		if(CM_THREAD_CURRENT_ID == getRenderThreadId())
+			CM_EXCEPT(InternalErrorException, "You are not allowed to call this method on the render thread!");
+
 		{
 			CM_LOCK_MUTEX(mRSContextMutex);
 

+ 3 - 8
CamelotRenderer/Source/CmResource.cpp

@@ -5,21 +5,16 @@
 namespace CamelotEngine
 {
 	Resource::Resource()
-		:mSize(0), mInitialized(false)
+		:mSize(0), mIsInitialized(false)
 	{
 		// We always generate a random UUID, and then overwrite it with the actual one 
 		// during loading if one was previously generated and saved.
 		mUUID = UUIDGenerator::generateRandom();
 	}
 
-	void Resource::init()
+	void Resource::initialize_internal()
 	{
-		if(!mInitialized)
-		{
-			initImpl();
-
-			mInitialized = true;
-		}
+		mIsInitialized = true;
 	}
 		
 	RTTITypeBase* Resource::getRTTIStatic()

+ 6 - 1
CamelotRenderer/Source/CmResourceHandle.cpp

@@ -21,6 +21,11 @@ namespace CamelotEngine
 		mData = std::shared_ptr<ResourceHandleData>(new ResourceHandleData());
 	}
 
+	bool ResourceHandleBase::isLoaded() const 
+	{ 
+		return (mData->mIsCreated && mData->mPtr != nullptr && mData->mPtr->isInitialized()); 
+	}
+
 	void ResourceHandleBase::resolve(std::shared_ptr<Resource> ptr) 
 	{ 
 		init(ptr);
@@ -43,7 +48,7 @@ namespace CamelotEngine
 		if(mData->mPtr)
 		{
 			mData->mUUID = mData->mPtr->getUUID();
-			mData->mIsResolved = true; 
+			mData->mIsCreated = true; 
 		}
 	}
 

+ 3 - 1
CamelotRenderer/Source/CmResources.cpp

@@ -44,7 +44,6 @@ namespace CamelotEngine
 		{
 			ResourceLoadResponsePtr resResponse = boost::any_cast<ResourceLoadResponsePtr>(res->getData());
 			
-			resResponse->rawResource->init();
 			resRequest->resource.resolve(resResponse->rawResource);
 
 			if(!gResources().metaExists_UUID(resResponse->rawResource->getUUID()))
@@ -250,6 +249,9 @@ namespace CamelotEngine
 
 	void Resources::save(BaseResourceHandle resource)
 	{
+		// TODO - Check if the resource is fully loaded or not. If its not loaded either wait for it to be loaded,
+		// or break out
+
 		assert(resource.get() != nullptr);
 
 		if(!metaExists_UUID(resource->getUUID()))

+ 1 - 1
CamelotRenderer/Source/CmShader.cpp

@@ -12,7 +12,7 @@ namespace CamelotEngine
 
 	}
 
-	void Shader::initImpl()
+	void Shader::initialize_internal()
 	{	}
 
 	TechniquePtr Shader::addTechnique(const String& renderSystem, const String& renderer)

+ 7 - 0
CamelotRenderer/Source/CmTextureManager.cpp

@@ -50,6 +50,13 @@ namespace CamelotEngine {
 
 		return ret;
     }
+	//-----------------------------------------------------------------------
+	TexturePtr TextureManager::createEmpty()
+	{
+		TexturePtr ret = TexturePtr(createImpl());
+
+		return ret;
+	}
     //-----------------------------------------------------------------------
 	bool TextureManager::isFormatSupported(TextureType ttype, PixelFormat format, int usage)
 	{

+ 30 - 17
CamelotRenderer/TODO.txt

@@ -19,12 +19,11 @@ Command buffer TODO:
  - My current approach doesn't allow multiple threads to use the RenderSystem (contexts should be handled differently)
    - Instead of requiring the user to constantly call setActiveContext, make the call peristent per thread. 
    - Store sequential thread idx in local thread storage, and then we can easily look up a context for a thread and
-     automatically use it, if it's set.
- - Make sure the user knows resources are shared between contexts. All resource updates are executed before rendering a frame, so whichever context updated the resource last,
-   was the version that will be used.
+     automatically use it, if it's set. (Use boost::thread_specific_ptr for local thread storage)
+ - Doing setPixels_async in the texture doesn't make sure that the user doesn't actually modify the provided PixelData after
+    that call.
 
  Texture updates:
-   - Make TextureData private to FreeImgImporter (as its not used anywhere else)
    - Make this per texture and apply when texture is applied:
 	 filterMode
 	 anisoLevel
@@ -32,8 +31,31 @@ Command buffer TODO:
 	 mipMapBias
    - Make sure resource deletion is handled on the proper thread
 
+Mesh
+ - Add initialize and initialize_internal
+ - Make sure MeshRTTI calls initialize properly
+ - Make sure FBX importer calls initialize properly
+
+GpuProgram/HighLevelGpuProgram
+ - Do a pass of refactoring
+ - Fix it up for multithreading
+  - In general everything needs to be checked
+  - Specifically HighLevelGpuParam::createParameters
+  - Add thread checks
+
+Make initialize & initialize_internal protected?
+ - Only their factories and RTTI classes need to access it (and they can be friends)
+ - Would need to modify HighLevelGpuProgram::mAssemblerProgram
+
+When saving a resource, make sure resource is properly loaded before saving
+ - Add blockUntilLoaded method to Resource
+  - Probably need a flag to make sure loading even started?
+    (Or not if I make Resource constructors and initialize methods protected)
+  - Make sure this is never called on the render thread
+  - Add doc to Resources::save that says it will block until render thread updates the resource
+  - Remove Response handlers from Resources
+
  Immediate:
-  - Resource updates shouldn't happen once per frame. Resources should be submitted to render thread immediately.
   - Port resource creation to use RenderContext (texture/mesh/shader/etc initialization and updates)
   - Make sure to add thread checks (surrounded by #if DEBUG) to Vertex/Index/Pixel buffers, textures, meshes, etc.
 
@@ -51,19 +73,11 @@ HIGH PRIORITY TODO:
 
 Mid priority TODO:
  - Add a field that tracks % of resource deserialization in BinarySerializer
-
- - Separate render thread
-   - CommandBuffer (technically it should be just a RenderQueue I think)
-   - Main thread updates components, finds visible meshes and creates render device. At end of execution it fills up render queue
-   - Render thread renders everything in the render queue, and also creates resources (although RenderQueue name doesn't make sense if its used for resources too)
-   - Before I start with this I should probably strip down render system to a bare minimum
-
  - GpuProgram default parameters might not be needed. The parameters change with each use of the gpu program anyway
  - Mesh loading:
   - Example Freefall mesh has one index per vertex, and there are 17k+ vertices. I think I need a post-process step that optimizes them.
   - Imported FBX meshes are too big
   - Search for all remaining "TODO PORT" comments and fix them
-  - How do I serialize derived classes, without rewriting all the base class serialization?
   - Ogre performed special DDS loading. I removed that. I'm not sure if I'll need to re-add it?
  - RTTI:
      When defining RTTIType like so: 
@@ -96,11 +110,10 @@ Optional TODO:
 
  -----------------------------------------------------------------------------------------------
 
-After everything is polished:
- - Make sure the renderer can run on a separate thread
-  - Command buffers that allow dx9, dx11 and opengl all use a separate render thread
- - Load texture mips separately so we can unload HQ textures from far away objects (like UE3)
+After everything is polished
  - Get 64bit version working
+ - DX11 render system
+ - Load texture mips separately so we can unload HQ textures from far away objects (like UE3)
  - Add Unified shader so I can easily switch between HLSL and GLSL shaders (they need same parameters usually, just different code)
     - Maybe just add support for Cg and force everyone to use that? - I'd like to be able to just switch out renderer in a single location and that everything keeps on working without 
 	  further modifications.

+ 7 - 0
TODODoc.txt

@@ -0,0 +1,7 @@
+ - Render system threading:
+   - Make a list of thread-safe RenderSystem classes
+    - For example HighLevelGpuProgram is thread safe but GpuProgram itself isn't
+    - Classes that are safe to use outside of the render thread: RenderSystem, Mesh, Texture, HighLevelGpuProgram, Material, Shader, Technique
+	- Classes that are only accessible from the render thread: GpuProgram, HardwarePixelBuffer, HardwareVertexBuffer, HardwareIndexBuffer
+  - Make sure the user knows resources are shared between contexts. All resource updates are executed 
+     before rendering a frame, so whichever context updated the resource last, was the version that will be used.