Browse Source

Fixed Renderer by properly updating dirty parameters and properly handling DrawList items
Updated Copy functionality on textures
Copy now automatically resolves multisampled textures
Fixed semantic issues with StdAlloc in various parts of code

Marko Pintera 11 years ago
parent
commit
4460630297
32 changed files with 359 additions and 179 deletions
  1. 1 0
      BansheeCore/BansheeCore.vcxproj
  2. 3 0
      BansheeCore/BansheeCore.vcxproj.filters
  3. 5 5
      BansheeCore/Include/BsCoreObject.h
  4. 11 0
      BansheeCore/Include/BsMaterialProxy.h
  5. 2 0
      BansheeCore/Include/BsMeshBase.h
  6. 2 2
      BansheeCore/Include/BsSceneObject.h
  7. 11 4
      BansheeCore/Include/BsTexture.h
  8. 1 1
      BansheeCore/Source/BsGpuParams.cpp
  9. 13 22
      BansheeCore/Source/BsMaterial.cpp
  10. 38 0
      BansheeCore/Source/BsMaterialProxy.cpp
  11. 1 0
      BansheeCore/Source/BsMesh.cpp
  12. 1 1
      BansheeCore/Source/BsSceneObject.cpp
  13. 38 23
      BansheeCore/Source/BsTexture.cpp
  14. 2 1
      BansheeCore/Source/BsTransientMesh.cpp
  15. 1 1
      BansheeD3D11RenderSystem/Include/BsD3D11Texture.h
  16. 3 3
      BansheeD3D11RenderSystem/Source/BsD3D11QueryManager.cpp
  17. 33 6
      BansheeD3D11RenderSystem/Source/BsD3D11Texture.cpp
  18. 1 1
      BansheeD3D9RenderSystem/Include/BsD3D9Texture.h
  19. 3 3
      BansheeD3D9RenderSystem/Source/BsD3D9QueryManager.cpp
  20. 50 59
      BansheeD3D9RenderSystem/Source/BsD3D9Texture.cpp
  21. 1 0
      BansheeGLRenderSystem/Include/BsGLPixelBuffer.h
  22. 16 3
      BansheeGLRenderSystem/Include/BsGLRenderTexture.h
  23. 1 1
      BansheeGLRenderSystem/Include/BsGLTexture.h
  24. 4 1
      BansheeGLRenderSystem/Source/BsGLFrameBufferObject.cpp
  25. 52 8
      BansheeGLRenderSystem/Source/BsGLPixelBuffer.cpp
  26. 3 3
      BansheeGLRenderSystem/Source/BsGLQueryManager.cpp
  27. 5 2
      BansheeGLRenderSystem/Source/BsGLRenderTexture.cpp
  28. 17 14
      BansheeGLRenderSystem/Source/BsGLTexture.cpp
  29. 28 3
      BansheeRenderer/Source/BsBansheeRenderer.cpp
  30. 4 3
      BansheeUtility/Include/BsFrameAlloc.h
  31. 4 4
      BansheeUtility/Include/BsStdHeaders.h
  32. 4 5
      SceneView.txt

+ 1 - 0
BansheeCore/BansheeCore.vcxproj

@@ -424,6 +424,7 @@
     <ClCompile Include="Source\BsCameraProxy.cpp" />
     <ClCompile Include="Source\BsCoreThread.cpp" />
     <ClCompile Include="Source\BsDrawList.cpp" />
+    <ClCompile Include="Source\BsMaterialProxy.cpp" />
     <ClCompile Include="Source\BsProfilerCPU.cpp" />
     <ClCompile Include="Source\BsDeferredCallManager.cpp" />
     <ClCompile Include="Source\BsDrawOps.cpp" />

+ 3 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -833,5 +833,8 @@
     <ClCompile Include="Source\BsRenderTargetManager.cpp">
       <Filter>Source Files\RenderSystem</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsMaterialProxy.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 5 - 5
BansheeCore/Include/BsCoreObject.h

@@ -211,7 +211,7 @@ namespace BansheeEngine
 	std::shared_ptr<Type> bs_core_ptr(Args &&...args)
 	{
 		return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
-			&CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<PtrDataAlloc>());
+			&CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<Type, PtrDataAlloc>());
 	}
 
 	/**
@@ -224,7 +224,7 @@ namespace BansheeEngine
 	std::shared_ptr<Type> bs_core_ptr(Args &&...args)
 	{
 		return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
-			&CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<GenAlloc>());
+			&CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<Type, GenAlloc>());
 	}
 
 	/**
@@ -237,7 +237,7 @@ namespace BansheeEngine
 	std::shared_ptr<Type> bs_core_ptr(Args &&...args)
 	{
 		return std::shared_ptr<Type>(bs_new<Type, GenAlloc>(std::forward<Args>(args)...),
-			&CoreObject::_deleteDelayed<Type, GenAlloc>, StdAlloc<GenAlloc>());
+			&CoreObject::_deleteDelayed<Type, GenAlloc>, StdAlloc<Type, GenAlloc>());
 	}
 
 	/**
@@ -249,7 +249,7 @@ namespace BansheeEngine
 	template<class Type, class MainAlloc>
 	std::shared_ptr<Type> bs_core_ptr(Type* data)
 	{
-		return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<GenAlloc>());  
+		return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<Type, GenAlloc>());  
 	}
 
 	/**
@@ -261,6 +261,6 @@ namespace BansheeEngine
 	template<class Type, class MainAlloc, class PtrDataAlloc>
 	std::shared_ptr<Type> bs_core_ptr(Type* data)
 	{
-		return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<PtrDataAlloc>());  
+		return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<Type, PtrDataAlloc>());  
 	}
 }

+ 11 - 0
BansheeCore/Include/BsMaterialProxy.h

@@ -73,6 +73,17 @@ namespace BansheeEngine
 			UINT32 numEntries;
 
 			FrameAlloc* owner;
+
+			/**
+			 * @brief	Allocates and constructs a new object. You must release it
+			 *			manually using the same frame allocator.
+			 */
+			static DirtyParamsInfo* create(FrameAlloc* alloc, UINT32 numParams);
+
+			/**
+			 * @brief	Deallocates and destructs a previously allocated params info object.
+			 */
+			static void destroy(DirtyParamsInfo* paramsInfo);
 		};
 
 		Vector<MaterialProxyPass> passes;

+ 2 - 0
BansheeCore/Include/BsMeshBase.h

@@ -171,6 +171,8 @@ namespace BansheeEngine
 		 * @brief	Creates a new core proxy from the current mesh data. Core proxy contains a snapshot of 
 		 *			mesh data normally managed on the sim thread (e.g. bounds).
 		 *
+		 * @param	subMeshIdx	Index of the sub-mesh to create a proxy for.
+		 *
 		 * @note	Sim thread only. 
 		 *			You generally need to update the core thread with a new proxy whenever core 
 		 *			dirty flag is set.

+ 2 - 2
BansheeCore/Include/BsSceneObject.h

@@ -346,7 +346,7 @@ namespace BansheeEngine
 
 			std::shared_ptr<T> gameObject(new (bs_alloc<T, PoolAlloc>()) T(mThisHandle,
 				std::forward<Args>(args)...),
-				&bs_delete<PoolAlloc, T>, StdAlloc<PoolAlloc>());
+				&bs_delete<PoolAlloc, T>, StdAlloc<T, PoolAlloc>());
 
 			GameObjectHandle<T> newComponent =
 				GameObjectHandle<T>(GameObjectManager::instance().registerObject(gameObject));
@@ -437,7 +437,7 @@ namespace BansheeEngine
 		{
 			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), "Specified type is not a valid Component.");
 
-			std::shared_ptr<T> gameObject(new (bs_alloc<T, PoolAlloc>()) T(), &bs_delete<PoolAlloc, T>, StdAlloc<PoolAlloc>());
+			std::shared_ptr<T> gameObject(new (bs_alloc<T, PoolAlloc>()) T(), &bs_delete<PoolAlloc, T>, StdAlloc<T, PoolAlloc>());
 			GameObjectHandle<T>(GameObjectManager::instance().registerObject(gameObject));
 
 			return gameObject;

+ 11 - 4
BansheeCore/Include/BsTexture.h

@@ -205,12 +205,19 @@ namespace BansheeEngine
 		void unlock();
 
 		/**
-		 * @brief	Copies the contents of this texture to another texture. Texture format
-		 * 			and size must match.
+		 * @brief	Copies the contents a subresource in this texture to another texture. 
+		 *			Texture format and size of the subresource must match.
+		 *
+		 *			You are allowed to copy from a multisampled to non-multisampled
+		 *			surface, which will resolve the multisampled surface before copying.
+		 *
+		 * @param	srcSubresourceIdx	Index of the subresource to copy from.
+		 * @param	destSubresourceIdx	Index of the subresource to copy to.
+		 * @param	target				Texture that contains the destination subresource.
 		 * 			
 		 * @note	Core thread only.
 		 */
-		void copy(TexturePtr& target);
+		void copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, TexturePtr& target);
 
 		/**
 		 * @brief	Reads data from the texture buffer into the provided buffer.
@@ -385,7 +392,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	copy
 		 */
-		virtual void copyImpl(TexturePtr& target) = 0;
+		virtual void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target) = 0;
 
 		/**
 		 * @copydoc	Resource::calculateSize

+ 1 - 1
BansheeCore/Source/BsGpuParams.cpp

@@ -259,7 +259,7 @@ namespace BansheeEngine
 		
 		if (frameAlloc != nullptr)
 		{
-			StdFrameAlloc<GpuParams> myAlloc(frameAlloc);
+			StdFrameAlloc<std::shared_ptr<GpuParams>> myAlloc(frameAlloc);
 			myClone = std::allocate_shared<GpuParams>(myAlloc, mParamDesc, PrivatelyConstruct());
 			myClone->mInternalData = std::allocate_shared<GpuParamsInternalData>(myAlloc);
 		}

+ 13 - 22
BansheeCore/Source/BsMaterial.cpp

@@ -774,17 +774,8 @@ namespace BansheeEngine
 				numDirtyParams++;
 		}
 
-		UINT32 sizeRequired = sizeof(MaterialProxy::DirtyParamsInfo) + numDirtyParams * sizeof(MaterialProxy::ParamsBindInfo);
-		UINT8* buffer = (UINT8*)frameAlloc->alloc(sizeRequired);
-
-		MaterialProxy::DirtyParamsInfo* dirtyParamsInfo = (MaterialProxy::DirtyParamsInfo*)buffer;
-		dirtyParamsInfo->numEntries = numDirtyParams;
-		dirtyParamsInfo->owner = frameAlloc;
+		MaterialProxy::DirtyParamsInfo* dirtyParamsInfo = MaterialProxy::DirtyParamsInfo::create(frameAlloc, numDirtyParams);
 		
-		buffer += sizeof(MaterialProxy::DirtyParamsInfo);
-		MaterialProxy::ParamsBindInfo* paramsInfoArray = (MaterialProxy::ParamsBindInfo*)buffer;
-		dirtyParamsInfo->entries = paramsInfoArray;
-
 		UINT32 idx = 0;
 		for (UINT32 i = 0; i < numPasses; i++)
 		{
@@ -793,48 +784,48 @@ namespace BansheeEngine
 
 			if (pass->hasVertexProgram() && params->mVertParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mVertParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mVertParams->_clone(frameAlloc);
 
 				idx++;
 			}
 
 			if (pass->hasFragmentProgram() && params->mFragParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mFragParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mFragParams->_clone(frameAlloc);
 
 				idx++;
 			}
 
 			if (pass->hasGeometryProgram() && params->mGeomParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mGeomParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mGeomParams->_clone(frameAlloc);
 
 				idx++;
 			}
 
 			if (pass->hasHullProgram() && params->mHullParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mHullParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mHullParams->_clone(frameAlloc);
 
 				idx++;
 			}
 
 			if (pass->hasDomainProgram() && params->mDomainParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mDomainParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mDomainParams->_clone(frameAlloc);
 
 				idx++;
 			}
 
 			if (pass->hasComputeProgram() && params->mComputeParams->_isCoreDirty())
 			{
-				paramsInfoArray[idx].paramsIdx = idx;
-				paramsInfoArray[idx].params = params->mComputeParams->_clone(frameAlloc);
+				dirtyParamsInfo->entries[idx].paramsIdx = idx;
+				dirtyParamsInfo->entries[idx].params = params->mComputeParams->_clone(frameAlloc);
 
 				idx++;
 			}

+ 38 - 0
BansheeCore/Source/BsMaterialProxy.cpp

@@ -0,0 +1,38 @@
+#include "BsMaterialProxy.h"
+#include "BsFrameAlloc.h"
+
+namespace BansheeEngine
+{
+	MaterialProxy::DirtyParamsInfo* MaterialProxy::DirtyParamsInfo::create(FrameAlloc* alloc, UINT32 numParams)
+	{
+		UINT32 sizeRequired = sizeof(DirtyParamsInfo) + numParams * sizeof(ParamsBindInfo);
+		UINT8* buffer = (UINT8*)alloc->alloc(sizeRequired);
+
+		MaterialProxy::DirtyParamsInfo* dirtyParamsInfo = (MaterialProxy::DirtyParamsInfo*)buffer;
+		dirtyParamsInfo->numEntries = numParams;
+		dirtyParamsInfo->owner = alloc;
+
+		buffer += sizeof(MaterialProxy::DirtyParamsInfo);
+		MaterialProxy::ParamsBindInfo* paramsInfoArray = (MaterialProxy::ParamsBindInfo*)buffer;
+		dirtyParamsInfo->entries = paramsInfoArray;
+
+		// Construct shared pointers
+		for (UINT32 i = 0; i < numParams; i++)
+		{
+			new (&dirtyParamsInfo->entries[i].params) GpuParamBlockPtr(nullptr);
+		}
+
+		return dirtyParamsInfo;
+	}
+
+	void MaterialProxy::DirtyParamsInfo::destroy(DirtyParamsInfo* paramsInfo)
+	{
+		// Destruct shared pointers
+		for (UINT32 i = 0; i < paramsInfo->numEntries; i++)
+		{
+			paramsInfo->entries[i].params.~shared_ptr();
+		}
+
+		paramsInfo->owner->dealloc((UINT8*)paramsInfo);
+	}
+}

+ 1 - 0
BansheeCore/Source/BsMesh.cpp

@@ -11,6 +11,7 @@
 #include "BsAABox.h"
 #include "BsVertexDataDesc.h"
 #include "BsResources.h"
+#include "BsFrameAlloc.h"
 
 namespace BansheeEngine
 {

+ 1 - 1
BansheeCore/Source/BsSceneObject.cpp

@@ -39,7 +39,7 @@ namespace BansheeEngine
 	HSceneObject SceneObject::createInternal(const String& name)
 	{
 		std::shared_ptr<SceneObject> sceneObjectPtr = std::shared_ptr<SceneObject>(new (bs_alloc<SceneObject, PoolAlloc>()) SceneObject(name), 
-			&bs_delete<PoolAlloc, SceneObject>, StdAlloc<PoolAlloc>());
+			&bs_delete<PoolAlloc, SceneObject>, StdAlloc<SceneObject, PoolAlloc>());
 		
 		HSceneObject sceneObject = GameObjectManager::instance().registerObject(sceneObjectPtr);
 		sceneObject->mThisHandle = sceneObject;

+ 38 - 23
BansheeCore/Source/BsTexture.cpp

@@ -170,37 +170,52 @@ namespace BansheeEngine
 		unlockImpl();
 	}
 
-	void Texture::copy(TexturePtr& target)
+	void Texture::copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, TexturePtr& target)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		if (target->getUsage() != this->getUsage() ||
-			target->getTextureType() != this->getTextureType())
-		{
+		if (target->getTextureType() != this->getTextureType())
 			BS_EXCEPT(InvalidParametersException, "Source and destination textures must be of same type and must have the same usage and type.");
-		}
 
-		if(getWidth() != target->getWidth() || getHeight() != target->getHeight() || getDepth() != target->getDepth())
-		{
-			BS_EXCEPT(InvalidParametersException, "Texture sizes don't match." \
-				" Width: " + toString(getWidth()) + "/" + toString(target->getWidth()) + 
-				" Height: " + toString(getHeight()) + "/" + toString(target->getHeight()) + 
-				" Depth: " + toString(getDepth()) + "/" + toString(target->getDepth()));
-		}
+		if (getFormat() != target->getFormat()) // Note: It might be okay to use different formats of the same size
+			BS_EXCEPT(InvalidParametersException, "Source and destination texture formats must match.");
 
-		if(getNumFaces() != target->getNumFaces())
-		{
-			BS_EXCEPT(InvalidParametersException, "Number of texture faces doesn't match." \
-				" Num faces: " + toString(getNumFaces()) + "/" + toString(target->getNumFaces()));
-		}
+		if (target->getMultisampleCount() > 0 && getMultisampleCount() != target->getMultisampleCount())
+			BS_EXCEPT(InvalidParametersException, "When copying to a multisampled texture, source texture must have the same number of samples.");
 
-		if(getNumMipmaps() != target->getNumMipmaps())
-		{
-			BS_EXCEPT(InvalidParametersException, "Number of mipmaps doesn't match." \
-				" Num mipmaps: " + toString(getNumMipmaps()) + "/" + toString(target->getNumMipmaps()));
-		}
+		UINT32 srcFace = 0;
+		UINT32 srcMipLevel = 0;
+
+		UINT32 destFace = 0;
+		UINT32 destMipLevel = 0;
+
+		mapFromSubresourceIdx(srcSubresourceIdx, srcFace, srcMipLevel);
+		target->mapFromSubresourceIdx(destSubresourceIdx, destFace, destMipLevel);
+
+		if (destFace >= getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
+
+		if (srcFace >= target->getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
+
+		if (srcMipLevel > getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Source mip level out of range. Valid range is [0, " + toString(getNumMipmaps()) + "]");
+
+		if (destMipLevel > target->getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Destination mip level out of range. Valid range is [0, " + toString(target->getNumMipmaps()) + "]");
+
+		UINT32 srcMipWidth = mWidth >> srcMipLevel;
+		UINT32 srcMipHeight = mHeight >> srcMipLevel;
+		UINT32 srcMipDepth = mDepth >> srcMipLevel;
+
+		UINT32 dstMipWidth = target->getWidth() >> destMipLevel;
+		UINT32 dstMipHeight = target->getHeight() >> destMipLevel;
+		UINT32 dstMipDepth = target->getDepth() >> destMipLevel;
+
+		if (srcMipWidth != dstMipWidth || srcMipHeight != dstMipHeight || srcMipDepth != dstMipDepth)
+			BS_EXCEPT(InvalidParametersException, "Source and destination sizes must match");
 
-		copyImpl(target);
+		copyImpl(srcFace, srcMipLevel, destFace, destMipLevel, target);
 	}
 
 	/************************************************************************/

+ 2 - 1
BansheeCore/Source/BsTransientMesh.cpp

@@ -2,6 +2,7 @@
 #include "BsVertexData.h"
 #include "BsBounds.h"
 #include "BsMeshHeap.h"
+#include "BsFrameAlloc.h"
 
 namespace BansheeEngine
 {
@@ -57,7 +58,7 @@ namespace BansheeEngine
 
 	MeshProxyPtr TransientMesh::_createProxy(UINT32 subMeshIdx)
 	{
-		MeshProxyPtr coreProxy = bs_shared_ptr<MeshProxy>();
+		MeshProxyPtr coreProxy = bs_shared_ptr<MeshProxy>();		
 		coreProxy->mesh = std::static_pointer_cast<MeshBase>(getThisPtr());
 		coreProxy->subMesh = mSubMeshes[0];
 		coreProxy->submeshIdx = subMeshIdx;

+ 1 - 1
BansheeD3D11RenderSystem/Include/BsD3D11Texture.h

@@ -56,7 +56,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc Texture::copyImpl
 		 */
-		void copyImpl(TexturePtr& target);
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target);
 
 		/**
 		 * @copydoc Texture::readData

+ 3 - 3
BansheeD3D11RenderSystem/Source/BsD3D11QueryManager.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 	EventQueryPtr D3D11QueryManager::createEventQuery() const
 	{
-		EventQueryPtr query = std::shared_ptr<D3D11EventQuery>(bs_new<D3D11EventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<GenAlloc>());  
+		EventQueryPtr query = std::shared_ptr<D3D11EventQuery>(bs_new<D3D11EventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<D3D11EventQuery>());
 		mEventQueries.push_back(query.get());
 
 		return query;
@@ -15,7 +15,7 @@ namespace BansheeEngine
 
 	TimerQueryPtr D3D11QueryManager::createTimerQuery() const
 	{
-		TimerQueryPtr query = std::shared_ptr<D3D11TimerQuery>(bs_new<D3D11TimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<GenAlloc>());  
+		TimerQueryPtr query = std::shared_ptr<D3D11TimerQuery>(bs_new<D3D11TimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<D3D11TimerQuery>());
 		mTimerQueries.push_back(query.get());
 
 		return query;
@@ -23,7 +23,7 @@ namespace BansheeEngine
 
 	OcclusionQueryPtr D3D11QueryManager::createOcclusionQuery(bool binary) const
 	{
-		OcclusionQueryPtr query = std::shared_ptr<D3D11OcclusionQuery>(bs_new<D3D11OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		OcclusionQueryPtr query = std::shared_ptr<D3D11OcclusionQuery>(bs_new<D3D11OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<D3D11OcclusionQuery>());
 		mOcclusionQueries.push_back(query.get());
 
 		return query;

+ 33 - 6
BansheeD3D11RenderSystem/Source/BsD3D11Texture.cpp

@@ -58,23 +58,37 @@ namespace BansheeEngine
 		Texture::destroy_internal();
 	}
 
-	void D3D11Texture::copyImpl(TexturePtr& target)
+	void D3D11Texture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target)
 	{
 		D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
 
+		UINT32 srcResIdx = D3D11CalcSubresource(srcMipLevel, srcFace, getNumMipmaps() + 1);
+		UINT32 destResIdx = D3D11CalcSubresource(destMipLevel, destFace, target->getNumMipmaps() + 1);
+
 		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
 		D3D11Device& device = rs->getPrimaryDevice();
-		device.getImmediateContext()->CopyResource(other->getDX11Resource(), mTex);
 
-		if (device.hasError())
+		if (getMultisampleCount() != target->getMultisampleCount()) // Resolving from MS to non-MS texture
 		{
-			String errorDescription = device.getErrorDescription();
-			BS_EXCEPT(RenderingAPIException, "D3D11 device cannot copy resource\nError Description:" + errorDescription);
+			device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
+		}
+		else
+		{
+			device.getImmediateContext()->CopySubresourceRegion(other->getDX11Resource(), destResIdx, 0, 0, 0, mTex, srcResIdx, nullptr);
+
+			if (device.hasError())
+			{
+				String errorDescription = device.getErrorDescription();
+				BS_EXCEPT(RenderingAPIException, "D3D11 device cannot copy subresource\nError Description:" + errorDescription);
+			}
 		}
 	}
 
 	PixelData D3D11Texture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 #if BS_PROFILING_ENABLED
 		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
 		{
@@ -138,6 +152,9 @@ namespace BansheeEngine
 
 	void D3D11Texture::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		PixelData myData = lock(GBL_READ_ONLY, mipLevel, face);
 
 #if BS_DEBUG_MODE
@@ -155,6 +172,9 @@ namespace BansheeEngine
 
 	void D3D11Texture::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		if(mUsage == TU_DYNAMIC)
 		{
 			PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mipLevel, face);
@@ -267,6 +287,7 @@ namespace BansheeEngine
 				"Requested: " + toString(mNumMipmaps) + ". Got: " + toString(desc.MipLevels - 1) + ".");
 		}
 
+		mDXGIFormat = desc.Format;
 		mDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
 
 		// Create texture view
@@ -529,6 +550,7 @@ namespace BansheeEngine
                "Requested: " + toString(mNumMipmaps) + ". Got: " + toString(desc.MipLevels - 1) + ".");
 		}
 
+		mDXGIFormat = desc.Format;
 		mDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
 
 		if((mUsage & TU_DEPTHSTENCIL) == 0)
@@ -594,8 +616,12 @@ namespace BansheeEngine
 
 	void* D3D11Texture::mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face, UINT32& rowPitch, UINT32& slicePitch)
 	{
+		// Note: I am creating and destroying a staging resource every time a texture is read. 
+		// Consider offering a flag on init that will keep this active all the time (at the cost of double memory).
+		// Reading is slow operation anyway so I don't believe doing it as we are now will influence it much.
+
 		if(!mStagingBuffer)
-			createStagingBuffer();
+			createStagingBuffer(); 
 
 		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
 		D3D11Device& device = rs->getPrimaryDevice();
@@ -607,6 +633,7 @@ namespace BansheeEngine
 	void D3D11Texture::unmapstagingbuffer()
 	{
 		unmap(mStagingBuffer);
+		SAFE_RELEASE(mStagingBuffer);
 	}
 
 	void* D3D11Texture::mapstaticbuffer(PixelData lock, UINT32 mipLevel, UINT32 face)

+ 1 - 1
BansheeD3D9RenderSystem/Include/BsD3D9Texture.h

@@ -116,7 +116,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc Texture::copy
 		 */
-		void copyImpl(TexturePtr& target);
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target);
 
 		/**
 		 * @copydoc Texture::readData

+ 3 - 3
BansheeD3D9RenderSystem/Source/BsD3D9QueryManager.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 	EventQueryPtr D3D9QueryManager::createEventQuery() const
 	{
-		EventQueryPtr query = std::shared_ptr<D3D9EventQuery>(bs_new<D3D9EventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<GenAlloc>());  
+		EventQueryPtr query = std::shared_ptr<D3D9EventQuery>(bs_new<D3D9EventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<D3D9EventQuery>());
 		mEventQueries.push_back(query.get());
 
 		return query;
@@ -15,7 +15,7 @@ namespace BansheeEngine
 
 	TimerQueryPtr D3D9QueryManager::createTimerQuery() const
 	{
-		TimerQueryPtr query = std::shared_ptr<D3D9TimerQuery>(bs_new<D3D9TimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<GenAlloc>());  
+		TimerQueryPtr query = std::shared_ptr<D3D9TimerQuery>(bs_new<D3D9TimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<D3D9TimerQuery>());
 		mTimerQueries.push_back(query.get());
 
 		return query;
@@ -23,7 +23,7 @@ namespace BansheeEngine
 
 	OcclusionQueryPtr D3D9QueryManager::createOcclusionQuery(bool binary) const
 	{
-		OcclusionQueryPtr query = std::shared_ptr<D3D9OcclusionQuery>(bs_new<D3D9OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		OcclusionQueryPtr query = std::shared_ptr<D3D9OcclusionQuery>(bs_new<D3D9OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<D3D9OcclusionQuery>());
 		mOcclusionQueries.push_back(query.get());
 
 		return query;

+ 50 - 59
BansheeD3D9RenderSystem/Source/BsD3D9Texture.cpp

@@ -67,6 +67,9 @@ namespace BansheeEngine
 
 	PixelData D3D9Texture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		if(mLockedBuffer != nullptr)
 			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
 
@@ -96,6 +99,9 @@ namespace BansheeEngine
 
 	void D3D9Texture::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		PixelData myData = lock(GBL_READ_ONLY, mipLevel, face);
 
 #if BS_DEBUG_MODE
@@ -113,6 +119,9 @@ namespace BansheeEngine
 
 	void D3D9Texture::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		if(mUsage == TU_DYNAMIC || mUsage == TU_STATIC)
 		{
 			PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mipLevel, face);
@@ -125,90 +134,72 @@ namespace BansheeEngine
 		}
 	}
 	
-	void D3D9Texture::copyImpl(TexturePtr& target)
+	void D3D9Texture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		if (target->getUsage() != getUsage() || target->getTextureType() != getTextureType())
-		{
-			BS_EXCEPT(InvalidParametersException, "Src. and dest. textures must be of same type and must have the same usage.");
-		}
+		if (getTextureType() == TEX_TYPE_1D || getTextureType() == TEX_TYPE_3D)
+			BS_EXCEPT(NotImplementedException, "Copy not implemented for 1D and 3D textures yet.");
 
         HRESULT hr;
 		D3D9Texture *other = static_cast<D3D9Texture*>(target.get());
-		RECT dstRC = { 0, 0, (LONG)(other->getWidth()), (LONG)(other->getHeight()) };
 
 		for (auto& resPair : mMapDeviceToTextureResources)
 		{
 			TextureResources* srcTextureResource = resPair.second;
 			TextureResources* dstTextureResource = other->getTextureResources(resPair.first);
 
-			// Plain copy for normal textures
-			if (getTextureType() == TEX_TYPE_2D && srcTextureResource->pNormTex != nullptr && 
-				dstTextureResource->pNormTex != nullptr)
+			IDirect3DSurface9 *sourceSurface = nullptr;
+			IDirect3DSurface9 *destSurface = nullptr;
+
+			if (getTextureType() == TEX_TYPE_2D && srcTextureResource->pNormTex != nullptr && dstTextureResource->pNormTex != nullptr)
 			{			
-				IDirect3DSurface9 *sourceSurface = 0;
-				if(FAILED(hr = srcTextureResource->pNormTex->GetSurfaceLevel(0, &sourceSurface)))
+				if(FAILED(hr = srcTextureResource->pNormTex->GetSurfaceLevel(srcMipLevel, &sourceSurface)))
 				{
 					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
 				}
 
-				IDirect3DSurface9 *destSurface = 0;			
-				if(FAILED(hr = dstTextureResource->pNormTex->GetSurfaceLevel(0, &destSurface)))
+				if(FAILED(hr = dstTextureResource->pNormTex->GetSurfaceLevel(destMipLevel, &destSurface)))
 				{
 					String msg = DXGetErrorDescription(hr);
-					SAFE_RELEASE(sourceSurface);
-					BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
 				}
-
-				if (FAILED(hr = resPair.first->StretchRect(sourceSurface, NULL, destSurface, &dstRC, D3DTEXF_NONE)))
+			}
+			else if (getTextureType() == TEX_TYPE_CUBE_MAP && srcTextureResource->pCubeTex != nullptr && dstTextureResource->pCubeTex != nullptr)
+			{				
+				IDirect3DSurface9 *sourceSurface = nullptr;
+				if (FAILED(hr = srcTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)srcFace, srcMipLevel, &sourceSurface)))
 				{
 					String msg = DXGetErrorDescription(hr);
-					SAFE_RELEASE(sourceSurface);
-					SAFE_RELEASE(destSurface);
-					BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
 				}
 
-				SAFE_RELEASE(sourceSurface);
-				SAFE_RELEASE(destSurface);
-			}
-			else if (getTextureType() == TEX_TYPE_CUBE_MAP && srcTextureResource->pCubeTex != nullptr && 
-				dstTextureResource->pCubeTex != nullptr)
-			{				
-				for (UINT32 face = 0; face < 6; face++)
+				IDirect3DSurface9 *destSurface = nullptr;
+				if (FAILED(hr = dstTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)destFace, destMipLevel, &destSurface)))
 				{
-					IDirect3DSurface9 *sourceSurface = 0;
-					if( FAILED(hr = srcTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &sourceSurface)))
-					{
-						String msg = DXGetErrorDescription(hr);
-						BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
-					}
-
-					IDirect3DSurface9 *destSurface = 0;
-					if( FAILED(hr = dstTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &destSurface)))
-					{
-						String msg = DXGetErrorDescription(hr);
-						SAFE_RELEASE(sourceSurface);
-						BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
-					}
-
-					if (FAILED(hr = resPair.first->StretchRect(sourceSurface, NULL, destSurface, &dstRC, D3DTEXF_NONE)))
-					{
-						String msg = DXGetErrorDescription(hr);
-						SAFE_RELEASE(sourceSurface);
-						SAFE_RELEASE(destSurface);
-						BS_EXCEPT(RenderingAPIException, "Couldn't blit: " + msg);
-					}
-
-					SAFE_RELEASE(sourceSurface);
-					SAFE_RELEASE(destSurface);
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
 				}
 			}
-			else
+
+			if (sourceSurface != nullptr && destSurface != nullptr)
 			{
-				BS_EXCEPT(NotImplementedException, "Copy to texture is implemented only for 2D and cube textures.");
+				if (sourceSurface->Pool != D3DPOOL_DEFAULT)
+					BS_EXCEPT(InvalidStateException, "Source surface must be in the default pool.");
+
+				if (destSurface->Pool != D3DPOOL_DEFAULT)
+					BS_EXCEPT(InvalidStateException, "Destination surface must be in the default pool.");
+
+				if (FAILED(hr = resPair.first->StretchRect(sourceSurface, NULL, destSurface, NULL, D3DTEXF_NONE)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "StretchRect failed during copy: " + msg);
+				}
 			}
+
+			SAFE_RELEASE(sourceSurface);
+			SAFE_RELEASE(destSurface);
 		}		
 	}
 	
@@ -373,7 +364,7 @@ namespace BansheeEngine
 			// Create AA surface
 			HRESULT hr = d3d9Device->CreateRenderTarget(mWidth, mHeight, d3dPF, 
 				mMultisampleType, mMultisampleQuality,
-				TRUE, // TODO - Possible performance issues? Need to check
+				TRUE, // TODO - Possible performance issues? Need to check. Other option is to use GetRenderTargetData when reading RT from CPU
 				&textureResources->pMultisampleSurface, NULL);
 
 			if (FAILED(hr))
@@ -389,14 +380,14 @@ namespace BansheeEngine
 
 			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
 
-			mIsBindableAsShaderResource = true; // Cannot bind AA surfaces
+			mIsBindableAsShaderResource = false; // Cannot bind AA surfaces
 		}
 		else if ((mUsage & TU_DEPTHSTENCIL) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
 		{
 			// Create AA depth stencil surface
 			HRESULT hr = d3d9Device->CreateDepthStencilSurface(mWidth, mHeight, d3dPF, 
 				mMultisampleType, mMultisampleQuality,
-				TRUE, // TODO - Possible performance issues? Need to check
+				TRUE, // TODO - Possible performance issues? Need to check. Other option is to use GetRenderTargetData when reading RT from CPU
 				&textureResources->pDepthStencilSurface, NULL);
 
 			if (FAILED(hr))
@@ -413,7 +404,7 @@ namespace BansheeEngine
 
 			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
 
-			mIsBindableAsShaderResource = true; // Cannot bind AA depth buffer
+			mIsBindableAsShaderResource = false; // Cannot bind AA depth buffer
 		}
 		else
 		{

+ 1 - 0
BansheeGLRenderSystem/Include/BsGLPixelBuffer.h

@@ -148,6 +148,7 @@ namespace BansheeEngine
 		GLuint mTextureID;
 		GLint mFace;
 		GLint mLevel;
+		UINT32 mMultisampleCount;
     };
 
 	/**

+ 16 - 3
BansheeGLRenderSystem/Include/BsGLRenderTexture.h

@@ -91,6 +91,18 @@ namespace BansheeEngine
          * @note	Thread safe.
          */
         virtual PixelFormat getSupportedAlternative(PixelFormat format);
+
+		/**
+		 * @brief	Returns a persistent FBO that is used as a
+		 *			source buffer for blit operations.
+		 */
+		GLuint getBlitReadFBO() const { return mBlitReadFBO; }
+
+		/**
+		 * @brief	Returns a persistent FBO that is used as a 
+		 *			destination buffer for blit operations.
+		 */
+		GLuint getBlitDrawFBO() const { return mBlitWriteFBO; }
     private:
         /** 
 		 * Frame buffer object properties for a certain texture format.
@@ -110,9 +122,6 @@ namespace BansheeEngine
 			bool valid;
         };
 
-        FormatProperties mProps[PF_COUNT];
-        GLuint mTempFBO;
-        
 		/**
 		 * @brief	Detect which internal formats are allowed to be used on render target 
 		 *			color or depth/stencil surfaces.
@@ -129,5 +138,9 @@ namespace BansheeEngine
 		 *			in the render target.
 		 */
         bool _tryPackedFormat(GLenum packedFormat);
+
+		FormatProperties mProps[PF_COUNT];
+		GLuint mBlitReadFBO;
+		GLuint mBlitWriteFBO;
     };
 }

+ 1 - 1
BansheeGLRenderSystem/Include/BsGLTexture.h

@@ -65,7 +65,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc Texture::copy
 		 */
-		void copyImpl(TexturePtr& target);
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target);
 
 		/**
 		 * @copydoc Texture::readData

+ 4 - 1
BansheeGLRenderSystem/Source/BsGLFrameBufferObject.cpp

@@ -89,12 +89,15 @@ namespace BansheeEngine
                     BS_EXCEPT(InvalidParametersException, ss.str());
                 }
 
+				// Note: I'm attaching textures to FBO while renderbuffers might yield better performance if I
+				// don't need to read from them
+
 	            mColor[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0_EXT + x, mColor[x].zoffset);
             }
             else
             {
                 // Detach
-                glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + x, GL_RENDERBUFFER_EXT, 0);
+                glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + x, 0, 0);
             }
         }
 

+ 52 - 8
BansheeGLRenderSystem/Source/BsGLPixelBuffer.cpp

@@ -98,7 +98,7 @@ namespace BansheeEngine
 									 GLint face, GLint level, GpuBufferUsage usage, 
 									 bool writeGamma, UINT32 multisampleCount):
 		GLPixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
-		mTarget(target), mFaceTarget(0), mTextureID(id), mFace(face), mLevel(level)
+		mTarget(target), mFaceTarget(0), mTextureID(id), mFace(face), mLevel(level), mMultisampleCount(multisampleCount)
 	{
 		GLint value = 0;
 	
@@ -149,6 +149,9 @@ namespace BansheeEngine
 		if((mUsage & TU_RENDERTARGET) != 0)
 			BS_EXCEPT(NotImplementedException, "Writing to render texture from CPU not supported.");
 
+		if ((mUsage & TU_DEPTHSTENCIL) != 0)
+			BS_EXCEPT(NotImplementedException, "Writing to depth stencil texture from CPU not supported.");
+
 		glBindTexture( mTarget, mTextureID );
 		if(PixelUtil::isCompressed(data.getFormat()))
 		{
@@ -274,12 +277,6 @@ namespace BansheeEngine
 
 	void GLTextureBuffer::download(const PixelData &data)
 	{
-		if((mUsage & TU_RENDERTARGET) != 0)
-			BS_EXCEPT(NotImplementedException, "Reading from render texture to CPU not supported."); // TODO: This needs to be implemented
-
-		if((mUsage & TU_DEPTHSTENCIL) != 0)
-			BS_EXCEPT(NotImplementedException, "Reading from depth stencil texture to CPU not supported."); // TODO: This needs to be implemented
-
 		if(data.getWidth() != getWidth() || data.getHeight() != getHeight() || data.getDepth() != getDepth())
 			BS_EXCEPT(InvalidParametersException, "only download of entire buffer is supported by GL");
 
@@ -368,7 +365,54 @@ namespace BansheeEngine
 
 	void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox)
 	{
-		BS_EXCEPT(NotImplementedException, "Not implemented.");
+		if (src->mMultisampleCount > 0 && mMultisampleCount == 0) // Resolving MS texture
+		{
+			if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE)
+				BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported.");
+
+			GLint currentFBO = 0;
+			glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFBO);
+
+			GLuint readFBO = GLRTTManager::instance().getBlitReadFBO();
+			GLuint drawFBO = GLRTTManager::instance().getBlitDrawFBO();
+
+			// Attach source texture
+			glBindFramebuffer(GL_FRAMEBUFFER, readFBO);
+			src->bindToFramebuffer(0, 0);
+
+			// Attach destination texture
+			glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
+			bindToFramebuffer(0, 0);
+
+			// Perform blit
+			glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
+			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
+
+			glReadBuffer(GL_COLOR_ATTACHMENT0);
+			glDrawBuffer(GL_COLOR_ATTACHMENT0);
+
+			glBlitFramebuffer(srcBox.left, srcBox.top, srcBox.right, srcBox.bottom, 
+				dstBox.left, dstBox.top, dstBox.right, dstBox.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+			// Restore the previously bound FBO
+			glBindFramebuffer(GL_FRAMEBUFFER, currentFBO);
+		}
+		else // Just plain copy
+		{
+			if (mMultisampleCount != src->mMultisampleCount)
+				BS_EXCEPT(InvalidParametersException, "When copying textures their multisample counts must match.");
+
+			if (mTarget == GL_TEXTURE_3D) // 3D textures can't have arrays so their Z coordinate is handled differently
+			{
+				glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, srcBox.front,
+					mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, dstBox.front, srcBox.getWidth(), srcBox.getHeight(), srcBox.getDepth());
+			}
+			else
+			{
+				glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, src->mFace,
+					mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, mFace, srcBox.getWidth(), srcBox.getHeight(), 1);
+			}
+		}		
 	}
 	
 	GLRenderBuffer::GLRenderBuffer(GLenum format, UINT32 width, UINT32 height, GLsizei numSamples):

+ 3 - 3
BansheeGLRenderSystem/Source/BsGLQueryManager.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 	EventQueryPtr GLQueryManager::createEventQuery() const
 	{
-		EventQueryPtr query = std::shared_ptr<GLEventQuery>(bs_new<GLEventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<GenAlloc>());  
+		EventQueryPtr query = std::shared_ptr<GLEventQuery>(bs_new<GLEventQuery>(), &QueryManager::deleteEventQuery, StdAlloc<GLEventQuery>());
 		mEventQueries.push_back(query.get());
 
 		return query;
@@ -15,7 +15,7 @@ namespace BansheeEngine
 
 	TimerQueryPtr GLQueryManager::createTimerQuery() const
 	{
-		TimerQueryPtr query = std::shared_ptr<GLTimerQuery>(bs_new<GLTimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<GenAlloc>());  
+		TimerQueryPtr query = std::shared_ptr<GLTimerQuery>(bs_new<GLTimerQuery>(), &QueryManager::deleteTimerQuery, StdAlloc<GLTimerQuery>());
 		mTimerQueries.push_back(query.get());
 
 		return query;
@@ -23,7 +23,7 @@ namespace BansheeEngine
 
 	OcclusionQueryPtr GLQueryManager::createOcclusionQuery(bool binary) const
 	{
-		OcclusionQueryPtr query = std::shared_ptr<GLOcclusionQuery>(bs_new<GLOcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		OcclusionQueryPtr query = std::shared_ptr<GLOcclusionQuery>(bs_new<GLOcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GLOcclusionQuery>());
 		mOcclusionQueries.push_back(query.get());
 
 		return query;

+ 5 - 2
BansheeGLRenderSystem/Source/BsGLRenderTexture.cpp

@@ -78,15 +78,18 @@ namespace BansheeEngine
 	}
 
 	GLRTTManager::GLRTTManager()
+		:mBlitReadFBO(0), mBlitWriteFBO(0)
     {
 		detectFBOFormats();
 		
-        glGenFramebuffersEXT(1, &mTempFBO);
+		glGenFramebuffersEXT(1, &mBlitReadFBO);
+		glGenFramebuffersEXT(1, &mBlitWriteFBO);
     }
 
 	GLRTTManager::~GLRTTManager()
 	{
-        glDeleteFramebuffersEXT(1, &mTempFBO);      
+		glDeleteFramebuffersEXT(1, &mBlitReadFBO);
+		glDeleteFramebuffersEXT(1, &mBlitWriteFBO);
 	}
 
 	bool GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)

+ 17 - 14
BansheeGLRenderSystem/Source/BsGLTexture.cpp

@@ -165,7 +165,7 @@ namespace BansheeEngine
 		Texture::destroy_internal();
 	}
 
-    GLenum GLTexture::getGLTextureTarget(void) const
+    GLenum GLTexture::getGLTextureTarget() const
     {
         switch(mTextureType)
         {
@@ -194,6 +194,9 @@ namespace BansheeEngine
 
 	PixelData GLTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		if(mLockedBuffer != nullptr)
 			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
 
@@ -221,42 +224,42 @@ namespace BansheeEngine
 
 	void GLTexture::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		getBuffer(face, mipLevel)->download(dest);
 	}
 
 	void GLTexture::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
 	{
+		if (mMultisampleCount > 0)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
 		getBuffer(face, mipLevel)->upload(src, src.getExtents());
 	}
 
-	void GLTexture::copyImpl(TexturePtr& target)
+	void GLTexture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, TexturePtr& target)
 	{
 		size_t numMips = std::min(getNumMipmaps(), target->getNumMipmaps());
 
-		GLTexture* glTexture = static_cast<GLTexture*>(target.get());
-		for (UINT32 face = 0; face < getNumFaces(); face++)
-		{
-			for(UINT32 mip = 0; mip <= numMips; mip++)
-			{
-				GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(face, mip).get());
+		GLTexture* destTex = static_cast<GLTexture*>(target.get());
+		GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());
 
-				glTexture->getBuffer(face, mip)->blitFromTexture(src);
-			}
-		}
+		destTex->getBuffer(destFace, destMipLevel)->blitFromTexture(src);
 	}
 
 	void GLTexture::createSurfaceList()
 	{
 		mSurfaceList.clear();
 		
-		for(UINT32 face=0; face<getNumFaces(); face++)
+		for(UINT32 face = 0; face < getNumFaces(); face++)
 		{
-			for(UINT32 mip=0; mip<=getNumMipmaps(); mip++)
+			for(UINT32 mip = 0; mip <= getNumMipmaps(); mip++)
 			{
                 GLPixelBuffer *buf = bs_new<GLTextureBuffer, PoolAlloc>(getGLTextureTarget(), mTextureID, face, mip,
 						static_cast<GpuBufferUsage>(mUsage), mHwGamma, mMultisampleCount);
+
 				mSurfaceList.push_back(bs_shared_ptr<GLPixelBuffer, PoolAlloc>(buf));
-                
                 if(buf->getWidth() == 0 || buf->getHeight() == 0 || buf->getDepth() == 0)
                 {
 					BS_EXCEPT(RenderingAPIException, 

+ 28 - 3
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -332,26 +332,51 @@ namespace BansheeEngine
 
 			RenderQueuePtr renderQueue = bs_shared_ptr<RenderQueue>();
 			const Vector<DrawOperation>& drawOps = drawList->getDrawOperations();
+
+			// Note: It is important that draw ops update happens after renderables are updated, so that
+			// renderable proxies properly update in case they both share the same material/mesh
 			for (auto& drawOp : drawOps)
 			{
-				// TODO - Created proxies should be temporary and only last one frame, and should
-				// be allocated using the frame allocator
+				// Note: It is assumed render operations queued in the draw list is going
+				// to change every frame so we create new proxies using frame allocator
+				// every frame. It /might/ be more efficient not to use frame allocator
+				// and only update when they actually change. That might also cause
+				// issue if material/mesh is used both in draw list and a Renderable
+
+				MaterialProxy::DirtyParamsInfo* dirtyParams = nullptr;
+				if (drawOp.material->_isCoreDirty(MaterialDirtyFlag::Params))
+				{
+					dirtyParams = drawOp.material->_getDirtyProxyParams(frameAlloc);
+				}
 
 				if (drawOp.material->_isCoreDirty(MaterialDirtyFlag::Proxy))
 				{
 					drawOp.material->_setActiveProxy(drawOp.material->_createProxy());
 					drawOp.material->_markCoreClean(MaterialDirtyFlag::Proxy);
+					drawOp.material->_markCoreClean(MaterialDirtyFlag::Material);
+				}
+				else
+				{
+					if (dirtyParams != nullptr)
+						drawOp.material->_markCoreClean(MaterialDirtyFlag::Params);
 				}
 
 				if (drawOp.mesh->_isCoreDirty(MeshDirtyFlag::Proxy))
 				{
 					drawOp.mesh->_setActiveProxy(drawOp.submeshIdx, drawOp.mesh->_createProxy(drawOp.submeshIdx));
 					drawOp.mesh->_markCoreClean(MeshDirtyFlag::Proxy);
+					drawOp.mesh->_markCoreClean(MeshDirtyFlag::Mesh);
 				}
 
 				MaterialProxyPtr materialProxy = drawOp.material->_getActiveProxy();
 				MeshProxyPtr meshProxy = drawOp.mesh->_getActiveProxy(drawOp.submeshIdx);
 
+				if (dirtyParams != nullptr)
+				{
+					gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::updateMaterialProxy, this,
+						materialProxy, dirtyParams));
+				}
+
 				float distanceToCamera = (camera->SO()->getPosition() - drawOp.worldPosition).length();
 				renderQueue->add(materialProxy, meshProxy, distanceToCamera);
 			}
@@ -388,7 +413,7 @@ namespace BansheeEngine
 		for (auto& rendererBuffer : proxy->rendererBuffers)
 			proxy->params[rendererBuffer.paramsIdx]->setParamBlockBuffer(rendererBuffer.slotIdx, rendererBuffer.buffer);
 
-		dirtyParams->owner->dealloc((UINT8*)dirtyParams);
+		MaterialProxy::DirtyParamsInfo::destroy(dirtyParams);
 	}
 
 	void BansheeRenderer::renderAllCore(float time)

+ 4 - 3
BansheeUtility/Include/BsFrameAlloc.h

@@ -102,11 +102,13 @@ namespace BansheeEngine
 			:mFrameAlloc(frameAlloc)
 		{ }
 
-		StdFrameAlloc(const StdFrameAlloc&) throw()
+		StdFrameAlloc(const StdFrameAlloc& alloc) throw()
+			:mFrameAlloc(alloc.mFrameAlloc)
 		{ }
 
 		template <class U>
-		StdFrameAlloc(const StdFrameAlloc<U>&) throw()
+		StdFrameAlloc(const StdFrameAlloc<U>& alloc) throw()
+			:mFrameAlloc(alloc.mFrameAlloc)
 		{ }
 
 		~StdFrameAlloc() throw()
@@ -169,7 +171,6 @@ namespace BansheeEngine
 			mFrameAlloc->dealloc((UINT8*)p);
 		}
 
-	private:
 		FrameAlloc* mFrameAlloc;
 	};
 

+ 4 - 4
BansheeUtility/Include/BsStdHeaders.h

@@ -140,7 +140,7 @@ namespace BansheeEngine
 	template<class Type, class AllocCategory, class... Args> 
 	std::shared_ptr<Type> bs_shared_ptr(Args &&... args) 
 	{
-		return std::allocate_shared<Type>(StdAlloc<AllocCategory>(), std::forward<Args>(args)...); 
+		return std::allocate_shared<Type>(StdAlloc<Type, AllocCategory>(), std::forward<Args>(args)...);
 	}
 
 	/**
@@ -149,7 +149,7 @@ namespace BansheeEngine
 	template<class Type, class... Args>
 	std::shared_ptr<Type> bs_shared_ptr(Args &&... args)
 	{
-		return std::allocate_shared<Type>(StdAlloc<GenAlloc>(), std::forward<Args>(args)...);
+		return std::allocate_shared<Type>(StdAlloc<Type, GenAlloc>(), std::forward<Args>(args)...);
 	}
 
 	/**
@@ -159,7 +159,7 @@ namespace BansheeEngine
 	template<class Type, class MainAlloc>
 	std::shared_ptr<Type> bs_shared_ptr(Type* data) 
 	{
-		return std::shared_ptr<Type>(data, &bs_delete<MainAlloc, Type>, StdAlloc<GenAlloc>());  
+		return std::shared_ptr<Type>(data, &bs_delete<MainAlloc, Type>, StdAlloc<Type, GenAlloc>());
 	}
 
 	/**
@@ -169,6 +169,6 @@ namespace BansheeEngine
 	template<class Type, class MainAlloc, class PtrDataAlloc>
 	std::shared_ptr<Type> bs_shared_ptr(Type* data) 
 	{
-		return std::shared_ptr<Type>(data, &bs_delete<MainAlloc, Type>, StdAlloc<PtrDataAlloc>());  
+		return std::shared_ptr<Type>(data, &bs_delete<MainAlloc, Type>, StdAlloc<Type, PtrDataAlloc>());
 	}
 }

+ 4 - 5
SceneView.txt

@@ -5,11 +5,10 @@ TODO:
 Weekend:
  - SceneGrid is very ugly. Consider using default lines for now and come back with a better approach later.
 
-Sending GPU parameters to core thread:
- - MaterialProxy needs to be allocatable via frame alloc
- - MeshProxy needs to be allocatable via frame alloc
-
-do _markAsClean on GpuParams even with transient stuff? If I update the buffer it should be safe
+ I have no way of read data from window framebuffer. Will need special methods for it?
+  - Think about is this even needed? If I do post-processing I'm going to draw everything to render textures and then
+    just blit to back buffer. I think.
+ OpenGL texture read/write from render textures isn't hooked up at all
 
 ----------------------------------------------------------------------
 Handles