Selaa lähdekoodia

Fully ported Mesh to GpuResource and removed get/setMeshData methods

Marko Pintera 12 vuotta sitten
vanhempi
sitoutus
606fd3a902

+ 4 - 1
BansheeEngine/Source/BsGUIWidget.cpp

@@ -2,6 +2,7 @@
 #include "BsGUIManager.h"
 #include "BsGUIManager.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 #include "BsGUILabel.h"
 #include "BsGUILabel.h"
+#include "CmApplication.h"
 #include "CmDeferredRenderContext.h"
 #include "CmDeferredRenderContext.h"
 #include "CmMaterial.h"
 #include "CmMaterial.h"
 #include "CmPass.h"
 #include "CmPass.h"
@@ -164,7 +165,9 @@ namespace BansheeEngine
 		UINT32 meshIdx = 0;
 		UINT32 meshIdx = 0;
 		for(auto& renderElem : meshDataPerRenderElement)
 		for(auto& renderElem : meshDataPerRenderElement)
 		{
 		{
-			mCachedMeshes[meshIdx]->setMeshData(renderElem.second.meshData);
+			gMainSyncedRC().writeSubresource(mCachedMeshes[meshIdx].getInternalPtr(), 0, *renderElem.second.meshData);
+			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+
 			mCachedMaterials[meshIdx] = renderElem.second.material;
 			mCachedMaterials[meshIdx] = renderElem.second.material;
 
 
 			meshIdx++;
 			meshIdx++;

+ 26 - 8
CamelotCore/Include/CmMesh.h

@@ -1,7 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
-#include "CmResource.h"
+#include "CmGpuResource.h"
 #include "CmMeshData.h"
 #include "CmMeshData.h"
 #include "CmVertexData.h"
 #include "CmVertexData.h"
 #include "CmIndexData.h"
 #include "CmIndexData.h"
@@ -23,22 +23,40 @@ namespace CamelotFramework
 		UINT32 indexCount;
 		UINT32 indexCount;
 	};
 	};
 
 
-	class CM_EXPORT Mesh : public Resource
+	class CM_EXPORT Mesh : public GpuResource
 	{
 	{
 	public:
 	public:
 		virtual ~Mesh();
 		virtual ~Mesh();
 
 
 		/**
 		/**
-		 * @brief	Mesh data that is used for initializing the mesh. Needs to be set before calling load.
+		 * @copydoc GpuResource::writeSubresource
 		 */
 		 */
-		void setMeshData(MeshDataPtr meshData);
-		void setMeshData_internal(MeshDataPtr meshData);
+		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data);
 
 
 		/**
 		/**
-		 * @brief	Gets the mesh data from the GPU. This method is slow so be careful when you call it.
+		 * @copydoc GpuResource::readSubresource
 		 */
 		 */
-		MeshDataPtr getMeshData();
-		void getMeshData_internal(AsyncOp& asyncOp);
+		virtual void readSubresource(UINT32 subresourceIdx, GpuResourceData& data);
+
+		/**
+		 * @brief	Allocates a buffer you may use for storage when reading a subresource. You
+		 * 			need to allocate such a buffer if you are calling "readSubresource".
+		 * 			
+		 * @note	This method is thread safe.
+		 */
+		MeshDataPtr allocateSubresourceBuffer(UINT32 subresourceIdx) const;
+
+		/**
+		 * @brief	TODO - Currently does nothing. But normally it should provide a way to map subresource index to
+		 * 			a specific submesh or buffer stream. Right now you can only work with entire mesh at once, not its subsets.
+		 */
+		void mapFromSubresourceIdx(UINT32 subresourceIdx) const {}
+
+		/**
+		 * @brief	TODO - Currently does nothing. But normally it should provide a way to map submesh or stream index to
+		 * 			a specific subresource index. Right now you can only work with entire mesh at once, not its subsets.
+		 */
+		UINT32 mapToSubresourceIdx() const { return 0; }
 
 
 		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
 		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
 
 

+ 2 - 7
CamelotCore/Include/CmMeshData.h

@@ -1,7 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
-#include "CmIReflectable.h"
+#include "CmGpuResourceData.h"
 #include "CmVertexBuffer.h"
 #include "CmVertexBuffer.h"
 #include "CmIndexBuffer.h"
 #include "CmIndexBuffer.h"
 #include "CmVertexDeclaration.h"
 #include "CmVertexDeclaration.h"
@@ -61,7 +61,7 @@ namespace CamelotFramework
 		UINT32 mNumElements;
 		UINT32 mNumElements;
 	};
 	};
 
 
-	class CM_EXPORT MeshData : public IReflectable
+	class CM_EXPORT MeshData : public GpuResourceData
 	{
 	{
 	public:
 	public:
 		struct IndexElementData
 		struct IndexElementData
@@ -213,11 +213,6 @@ namespace CamelotFramework
 
 
 		vector<VertexElement>::type getVertexElements() const;
 		vector<VertexElement>::type getVertexElements() const;
 
 
-		void allocateInternalBuffer();
-		void allocateInternalBuffer(UINT32 numBytes);
-
-		UINT8* getData() const { return mData; }
-
 		static MeshDataPtr combine(const vector<MeshDataPtr>::type& elements);
 		static MeshDataPtr combine(const vector<MeshDataPtr>::type& elements);
 
 
 	protected:
 	protected:

+ 1 - 1
CamelotCore/Include/CmMeshDataRTTI.h

@@ -11,7 +11,7 @@ namespace CamelotFramework
 	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::IndexElementData);
 	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::IndexElementData);
 	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
 	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
 
 
-	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, IReflectable, MeshDataRTTI>
+	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, GpuResourceData, MeshDataRTTI>
 	{
 	{
 	private:
 	private:
 		VertexElement& getVertexElementData(MeshData* obj, UINT32 arrayIdx)
 		VertexElement& getVertexElementData(MeshData* obj, UINT32 arrayIdx)

+ 67 - 70
CamelotCore/Source/CmMesh.cpp

@@ -27,19 +27,14 @@ namespace CamelotFramework
 	{
 	{
 	}
 	}
 
 
-	void Mesh::setMeshData(MeshDataPtr meshData)
-	{
-		RenderSystem::instancePtr()->queueCommand(boost::bind(&Mesh::setMeshData_internal, this, meshData), true);
-	}
-
-	void Mesh::setMeshData_internal(MeshDataPtr meshData)
+	void Mesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
 	{
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 		THROW_IF_NOT_RENDER_THREAD;
 
 
-		if(meshData == nullptr)
-		{
-			CM_EXCEPT(InvalidParametersException, "Cannot load mesh. Mesh data is null.");
-		}
+		if(data.getTypeId() != TID_MeshData)
+			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
+
+		const MeshData& meshData = static_cast<const MeshData&>(data);
 
 
 		mSubMeshes.clear();
 		mSubMeshes.clear();
 
 
@@ -50,30 +45,30 @@ namespace CamelotFramework
 			CM_DELETE(mIndexData, IndexData, PoolAlloc);
 			CM_DELETE(mIndexData, IndexData, PoolAlloc);
 
 
 		// Submeshes
 		// Submeshes
-		for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
+		for(UINT32 i = 0; i < meshData.getNumSubmeshes(); i++)
 		{
 		{
-			UINT32 numIndices = meshData->getNumIndices(i);
+			UINT32 numIndices = meshData.getNumIndices(i);
 
 
 			if(numIndices > 0)
 			if(numIndices > 0)
 			{
 			{
-				mSubMeshes.push_back(SubMesh(meshData->getIndexBufferOffset(i), numIndices));
+				mSubMeshes.push_back(SubMesh(meshData.getIndexBufferOffset(i), numIndices));
 			}
 			}
 		}
 		}
 
 
 		// Indices
 		// Indices
 		mIndexData = CM_NEW(IndexData, PoolAlloc) IndexData();
 		mIndexData = CM_NEW(IndexData, PoolAlloc) IndexData();
 
 
-		mIndexData->indexCount = meshData->getNumIndices();
+		mIndexData->indexCount = meshData.getNumIndices();
 		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
 		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
-			meshData->getIndexType(),
+			meshData.getIndexType(),
 			mIndexData->indexCount, 
 			mIndexData->indexCount, 
 			GBU_STATIC);
 			GBU_STATIC);
 
 
 		UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
 		UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
-		UINT32 idxElementSize = meshData->getIndexElementSize();
+		UINT32 idxElementSize = meshData.getIndexElementSize();
 
 
-		UINT32 indicesSize = meshData->getIndexBufferSize();
-		UINT8* srcIdxData = meshData->getIndexData(); 
+		UINT32 indicesSize = meshData.getIndexBufferSize();
+		UINT8* srcIdxData = meshData.getIndexData(); 
 
 
 		memcpy(idxData, srcIdxData, indicesSize);
 		memcpy(idxData, srcIdxData, indicesSize);
 
 
@@ -82,15 +77,15 @@ namespace CamelotFramework
 		// Vertices
 		// Vertices
 		mVertexData = CM_NEW(VertexData, PoolAlloc) VertexData();
 		mVertexData = CM_NEW(VertexData, PoolAlloc) VertexData();
 
 
-		mVertexData->vertexCount = meshData->getNumVertices();
-		mVertexData->vertexDeclaration = meshData->createDeclaration();
+		mVertexData->vertexCount = meshData.getNumVertices();
+		mVertexData->vertexDeclaration = meshData.createDeclaration();
 
 
-		for(UINT32 i = 0; i <= meshData->getMaxStreamIdx(); i++)
+		for(UINT32 i = 0; i <= meshData.getMaxStreamIdx(); i++)
 		{
 		{
-			if(!meshData->hasStream(i))
+			if(!meshData.hasStream(i))
 				continue;
 				continue;
 
 
-			UINT32 streamSize = meshData->getStreamSize(i);
+			UINT32 streamSize = meshData.getStreamSize(i);
 
 
 			VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
 			VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
 				mVertexData->vertexDeclaration->getVertexSize(i),
 				mVertexData->vertexDeclaration->getVertexSize(i),
@@ -99,10 +94,10 @@ namespace CamelotFramework
 
 
 			mVertexData->setBuffer(i, vertexBuffer);
 			mVertexData->setBuffer(i, vertexBuffer);
 
 
-			UINT8* srcVertBufferData = meshData->getStreamData(i);
+			UINT8* srcVertBufferData = meshData.getStreamData(i);
 			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
 			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
 
 
-			UINT32 bufferSize = meshData->getStreamSize(i);
+			UINT32 bufferSize = meshData.getStreamSize(i);
 
 
 			memcpy(vertBufferData, srcVertBufferData, bufferSize);
 			memcpy(vertBufferData, srcVertBufferData, bufferSize);
 
 
@@ -110,30 +105,35 @@ namespace CamelotFramework
 		}
 		}
 	}
 	}
 
 
-	MeshDataPtr Mesh::getMeshData()
+	void Mesh::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
 	{
 	{
-		AsyncOp op = RenderSystem::instancePtr()->queueReturnCommand(boost::bind(&Mesh::getMeshData_internal, this, _1), true);
+		THROW_IF_NOT_RENDER_THREAD;
 
 
-		return op.getReturnValue<MeshDataPtr>();
-	}
+		if(data.getTypeId() != TID_MeshData)
+			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
 
 
-	void Mesh::getMeshData_internal(AsyncOp& asyncOp)
-	{
 		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
 		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
 		if(mIndexData)
 		if(mIndexData)
 			indexType = mIndexData->indexBuffer->getType();
 			indexType = mIndexData->indexBuffer->getType();
 
 
-		MeshDataPtr meshData(CM_NEW(MeshData, PoolAlloc) MeshData(mVertexData->vertexCount, indexType),
-			&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
+		MeshData& meshData = static_cast<MeshData&>(data);
 
 
-		meshData->beginDesc();
 		if(mIndexData)
 		if(mIndexData)
 		{
 		{
 			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
 			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
 			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
 			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
 
 
 			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
 			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-				meshData->addSubMesh(mSubMeshes[i].indexCount, i);
+			{
+				UINT8* indices = nullptr;
+
+				if(indexType == IndexBuffer::IT_16BIT)
+					indices = (UINT8*)meshData.getIndices16(i);
+				else
+					indices = (UINT8*)meshData.getIndices32(i);
+
+				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
+			}
 
 
 			mIndexData->indexBuffer->unlock();
 			mIndexData->indexBuffer->unlock();
 		}
 		}
@@ -146,44 +146,33 @@ namespace CamelotFramework
 			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
 			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
 			{
 			{
 				VertexBufferPtr vertexBuffer = iter->second;
 				VertexBufferPtr vertexBuffer = iter->second;
-				UINT32 vertexSize = vertexBuffer->getVertexSize();
+				UINT32 bufferSize = vertexBuffer->getVertexSize() * vertexBuffer->getNumVertices();
+				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
 
 
-				UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
-				for(UINT32 j = 0; j < numElements; j++)
-				{
-					const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
-					VertexElementType type = element->getType();
-					VertexElementSemantic semantic = element->getSemantic(); 
-					UINT32 semanticIdx = element->getSemanticIdx();
-					UINT32 offset = element->getOffset();
-					UINT32 elemSize = element->getSize();
+				UINT8* dest = meshData.getStreamData(streamIdx);
+				memcpy(dest, vertDataPtr, bufferSize);
 
 
-					meshData->addVertElem(type, semantic, semanticIdx, streamIdx);
-				}
+				vertexBuffer->unlock();
 
 
 				streamIdx++;
 				streamIdx++;
 			}
 			}
 		}
 		}
-		meshData->endDesc();
+	}
 
 
+	MeshDataPtr Mesh::allocateSubresourceBuffer(UINT32 subresourceIdx) const
+	{
+		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
 		if(mIndexData)
 		if(mIndexData)
-		{
-			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
-			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
-
-			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-			{
-				UINT8* indices = nullptr;
-
-				if(indexType == IndexBuffer::IT_16BIT)
-					indices = (UINT8*)meshData->getIndices16(i);
-				else
-					indices = (UINT8*)meshData->getIndices32(i);
+			indexType = mIndexData->indexBuffer->getType();
 
 
-				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
-			}
+		MeshDataPtr meshData(CM_NEW(MeshData, PoolAlloc) MeshData(mVertexData->vertexCount, indexType),
+			&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
 
 
-			mIndexData->indexBuffer->unlock();
+		meshData->beginDesc();
+		if(mIndexData)
+		{
+			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
+				meshData->addSubMesh(mSubMeshes[i].indexCount, i);
 		}
 		}
 
 
 		if(mVertexData)
 		if(mVertexData)
@@ -194,19 +183,27 @@ namespace CamelotFramework
 			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
 			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
 			{
 			{
 				VertexBufferPtr vertexBuffer = iter->second;
 				VertexBufferPtr vertexBuffer = iter->second;
-				UINT32 bufferSize = vertexBuffer->getVertexSize() * vertexBuffer->getNumVertices();
-				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
+				UINT32 vertexSize = vertexBuffer->getVertexSize();
 
 
-				UINT8* dest = meshData->getStreamData(streamIdx);
-				memcpy(dest, vertDataPtr, bufferSize);
+				UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
+				for(UINT32 j = 0; j < numElements; j++)
+				{
+					const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
+					VertexElementType type = element->getType();
+					VertexElementSemantic semantic = element->getSemantic(); 
+					UINT32 semanticIdx = element->getSemanticIdx();
+					UINT32 offset = element->getOffset();
+					UINT32 elemSize = element->getSize();
 
 
-				vertexBuffer->unlock();
+					meshData->addVertElem(type, semantic, semanticIdx, streamIdx);
+				}
 
 
 				streamIdx++;
 				streamIdx++;
 			}
 			}
 		}
 		}
+		meshData->endDesc();
 
 
-		asyncOp.completeOperation(meshData);
+		return meshData;
 	}
 	}
 
 
 	RenderOperation Mesh::getRenderOperation(UINT32 subMeshIdx) const
 	RenderOperation Mesh::getRenderOperation(UINT32 subMeshIdx) const
@@ -234,7 +231,7 @@ namespace CamelotFramework
 		// TODO Low priority - Initialize an empty mesh. A better way would be to only initialize the mesh
 		// TODO Low priority - Initialize an empty mesh. A better way would be to only initialize the mesh
 		// once we set the proper mesh data (then we don't have to do it twice), but this makes the code less complex.
 		// once we set the proper mesh data (then we don't have to do it twice), but this makes the code less complex.
 		// Consider changing it if there are performance issues.
 		// Consider changing it if there are performance issues.
-		setMeshData_internal(MeshManager::instance().getNullMeshData());
+		writeSubresource(0, *MeshManager::instance().getNullMeshData());
 
 
 		Resource::initialize_internal();
 		Resource::initialize_internal();
 	}
 	}

+ 0 - 10
CamelotCore/Source/CmMeshData.cpp

@@ -173,16 +173,6 @@ namespace CamelotFramework
 		return false;
 		return false;
 	}
 	}
 
 
-	void MeshData::allocateInternalBuffer()
-	{
-		mData = CM_NEW_BYTES(getInternalBufferSize(), ScratchAlloc); // TODO! - Not cleaned anywhere, because I won't be using this in the end
-	}
-
-	void MeshData::allocateInternalBuffer(UINT32 numBytes)
-	{
-		mData = CM_NEW_BYTES(numBytes, ScratchAlloc); // TODO! - Not cleaned anywhere, because I won't be using this in the end
-	}
-
 	UINT32 MeshData::getInternalBufferSize()
 	UINT32 MeshData::getInternalBufferSize()
 	{
 	{
 		return getIndexBufferSize() + getStreamSize();
 		return getIndexBufferSize() + getStreamSize();

+ 21 - 3
CamelotCore/Source/CmMeshRTTI.h

@@ -2,15 +2,33 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmRTTIType.h"
 #include "CmRTTIType.h"
+#include "CmApplication.h"
 #include "CmMesh.h"
 #include "CmMesh.h"
 #include "CmMeshManager.h"
 #include "CmMeshManager.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
-	class MeshRTTI : public RTTIType<Mesh, Resource, MeshRTTI>
+	class MeshRTTI : public RTTIType<Mesh, GpuResource, MeshRTTI>
 	{
 	{
-		MeshDataPtr getMeshData(Mesh* obj) { return obj->getMeshData(); }
-		void setMeshData(Mesh* obj, MeshDataPtr meshData) { obj->setMeshData(meshData); }
+		MeshDataPtr getMeshData(Mesh* obj) 
+		{ 
+			MeshDataPtr meshData = obj->allocateSubresourceBuffer(0);
+
+			GpuResourcePtr sharedMeshPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
+
+			gMainSyncedRC().readSubresource(sharedMeshPtr, 0, *meshData);
+			gMainSyncedRC().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
+
+			return meshData;
+		}
+
+		void setMeshData(Mesh* obj, MeshDataPtr meshData) 
+		{ 
+			GpuResourcePtr sharedMeshPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
+
+			gMainSyncedRC().writeSubresource(sharedMeshPtr, 0, *meshData);
+			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+		}
 
 
 	public:
 	public:
 		MeshRTTI()
 		MeshRTTI()

+ 4 - 0
CamelotCore/Source/CmTexture.cpp

@@ -93,6 +93,8 @@ namespace CamelotFramework {
 
 
 	void Texture::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
 	void Texture::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
 	{
 	{
+		THROW_IF_NOT_RENDER_THREAD;
+
 		if(data.getTypeId() != TID_PixelData)
 		if(data.getTypeId() != TID_PixelData)
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 
 
@@ -109,6 +111,8 @@ namespace CamelotFramework {
 
 
 	void Texture::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
 	void Texture::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
 	{
 	{
+		THROW_IF_NOT_RENDER_THREAD;
+
 		if(data.getTypeId() != TID_PixelData)
 		if(data.getTypeId() != TID_PixelData)
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 
 

+ 3 - 1
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -1,5 +1,6 @@
 #include "CmFBXImporter.h"
 #include "CmFBXImporter.h"
 #include "CmResource.h"
 #include "CmResource.h"
+#include "CmApplication.h"
 #include "CmDebug.h"
 #include "CmDebug.h"
 #include "CmDataStream.h"
 #include "CmDataStream.h"
 #include "CmPath.h"
 #include "CmPath.h"
@@ -50,7 +51,8 @@ namespace CamelotFramework
 		HMesh mesh = Mesh::create();
 		HMesh mesh = Mesh::create();
 
 
 		mesh.waitUntilLoaded();
 		mesh.waitUntilLoaded();
-		mesh->setMeshData(meshData);
+		gMainSyncedRC().writeSubresource(mesh.getInternalPtr(), 0, *meshData);
+		gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 
 
 		return mesh;
 		return mesh;
 	}
 	}

+ 3 - 1
TODODoc.txt

@@ -13,4 +13,6 @@
   - Texture limitations: Only 1D, 2D, 3D and Cube textures (and their samplers) are supported. Support for multisampled textures
   - Texture limitations: Only 1D, 2D, 3D and Cube textures (and their samplers) are supported. Support for multisampled textures
      is included where necessary to implement render targets. Support for texture arrays and is not included.
      is included where necessary to implement render targets. Support for texture arrays and is not included.
  - Multiple inheritance is not supported on any class that is serialized with the help of RTTI. If you use it you can expect
  - Multiple inheritance is not supported on any class that is serialized with the help of RTTI. If you use it you can expect
-   very weird issues.
+   very weird issues.
+ - If you're creating a hierarchy of classes with RTTI support, ALL classes in the hierarchy must have RTTI implementations. You cannot just leave
+   some out, even if they contain no data. This would create incomplete RTTI class hierarchy which can cause various issues.