Просмотр исходного кода

Modified how textures get locked/unlocked

Marko Pintera 13 лет назад
Родитель
Сommit
6075746884

+ 49 - 52
CamelotD3D11RenderSystem/Include/CmD3D11Texture.h

@@ -5,77 +5,74 @@
 
 namespace CamelotEngine
 {
-	class D3D11Texture : public Texture
-	{
-	public:
-		~D3D11Texture();
-
+	class D3D11Texture : public Texture
+	{
+	public:
+		~D3D11Texture();
+
+		ID3D11Resource* getDX11Resource() const { return mTex; }
+	protected:
+		D3D11Texture();
+
+		ID3D11Texture1D* m1DTex;
+		ID3D11Texture2D* m2DTex;
+		ID3D11Texture3D* m3DTex;	
+		ID3D11Resource* mTex;		
+
+		ID3D11ShaderResourceView* mShaderResourceView;
+		D3D11_SHADER_RESOURCE_VIEW_DESC mSRVDesc;
+
+		ID3D11Resource* mStagingBuffer;
+		PixelData* mStaticBuffer;
+		UINT32 mLockedSubresourceIdx;
+		bool mLockedForReading;
+
 		/**
-		 * @copydoc Texture::setRawPixels_internal
+		 * @copydoc Texture::lockImpl
 		 */
-		void setRawPixels_internal(const PixelData& data, UINT32 face = 0, UINT32 mip = 0);
-
+		PixelData lockImpl(LockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
+
 		/**
-		 * @copydoc Texture::getRawPixels_internal
-		 */
-		void getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op);
-
+		 * @copydoc Texture::unlockImpl
+		 */
+		void unlockImpl();
+
 		/**
 		 * @copydoc Texture::copy_internal
-		 */
-		void copy_internal(TexturePtr& target);
-
-		PixelData lock(LockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
-		void unlock();
-
-		ID3D11Resource* getDX11Resource() const { return mTex; }
-	protected:
-		D3D11Texture();
-
-		ID3D11Texture1D* m1DTex;
-		ID3D11Texture2D* m2DTex;
-		ID3D11Texture3D* m3DTex;	
-		ID3D11Resource* mTex;		
-
-		ID3D11ShaderResourceView* mShaderResourceView;
-		D3D11_SHADER_RESOURCE_VIEW_DESC mSRVDesc;
-
-		ID3D11Resource* mStagingBuffer;
-		PixelData* mStaticBuffer;
-		UINT32 mLockedSubresourceIdx;
-		bool mLockedForReading;
-
-		/// internal method, create a blank normal 1D Dtexture
-		void _create1DTex();
-		/// internal method, create a blank normal 2D texture
-		void _create2DTex();
-		/// internal method, create a blank cube texture
-		void _create3DTex();
-
-		void _createStagingBuffer();
+		 */
+		void copyImpl(TexturePtr& target);
+
+		/// internal method, create a blank normal 1D Dtexture
+		void _create1DTex();
+		/// internal method, create a blank normal 2D texture
+		void _create2DTex();
+		/// internal method, create a blank cube texture
+		void _create3DTex();
+
+		void _createStagingBuffer();
 
 		void* _map(ID3D11Resource* res, D3D11_MAP flags, UINT32 mipLevel, UINT32 face);
 		void _unmap(ID3D11Resource* res);
 
 		void* _mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face);
 		void _unmapstagingbuffer();
-		
-		void* _mapstaticbuffer(PixelData lock, UINT32 mipLevel, UINT32 slice);
-		void _unmapstaticbuffer();
-
+		
+		void* _mapstaticbuffer(PixelData lock, UINT32 mipLevel, UINT32 slice);
+		void _unmapstaticbuffer();
+
 		/**
 		 * @brief	Resource::initialize_internal
 		 */
-		void initialize_internal();
-
+		void initialize_internal();
+
 		/**
 		 * @copydoc Texture::createInternalResourcesImpl
 		 */
-		void createInternalResourcesImpl();
-		
+		void createInternalResourcesImpl();
+		
 		/**
 		 * @copydoc Texture::freeInternalResourcesImpl
 		 */
-		void freeInternalResourcesImpl();
+		void freeInternalResourcesImpl();
 	};
 }

+ 9 - 102
CamelotD3D11RenderSystem/Source/CmD3D11Texture.cpp

@@ -34,106 +34,8 @@ namespace CamelotEngine
 		freeInternalResources();			
 	}
 
-	void D3D11Texture::setRawPixels_internal(const PixelData& data, UINT32 face, UINT32 mip)
+	void D3D11Texture::copyImpl(TexturePtr& target)
 	{
-		THROW_IF_NOT_RENDER_THREAD
-
-		if(mip < 0 || mip > mNumMipmaps)
-			CM_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mip) + ". Min is 0, max is " + toString(mNumMipmaps));
-
-		if(face < 0 || face > getNumFaces())
-			CM_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(getNumFaces()));
-
-		if(mFormat != data.format)
-			CM_EXCEPT(InvalidParametersException, "Provided PixelData has invalid format. Needed: " + toString(mFormat) + ". Got: " + toString(data.format));
-
-		if(mWidth != data.getWidth() || mHeight != data.getHeight() || mDepth != data.getDepth())
-		{
-			CM_EXCEPT(InvalidParametersException, "Provided PixelData size doesn't match the texture size." \
-				" Width: " + toString(mWidth) + "/" + toString(data.getWidth()) + 
-				" Height: " + toString(mHeight) + "/" + toString(data.getHeight()) + 
-				" Depth: " + toString(mDepth) + "/" + toString(data.getDepth()));
-		}
-
-		PixelData myData = lock(HBL_WRITE_ONLY_DISCARD, mip, face);
-		memcpy(myData.data, data.data, data.getConsecutiveSize());
-		unlock();
-	}
-
-	void D3D11Texture::getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op)
-	{
-		THROW_IF_NOT_RENDER_THREAD;
-
-		if(mip < 0 || mip > mNumMipmaps)
-			CM_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mip) + ". Min is 0, max is " + toString(mNumMipmaps));
-
-		if(face < 0 || mip > getNumFaces())
-			CM_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(getNumFaces()));
-
-		UINT32 numMips = getNumMipmaps();
-
-		UINT32 totalSize = 0;
-		UINT32 width = getWidth();
-		UINT32 height = getHeight();
-		UINT32 depth = getDepth();
-
-		for(UINT32 j = 0; j <= mip; j++)
-		{
-			totalSize = PixelUtil::getMemorySize(width, height, depth, mFormat);
-
-			if(width != 1) width /= 2;
-			if(height != 1) height /= 2;
-			if(depth != 1) depth /= 2;
-		}
-
-		UINT8* buffer = new UINT8[totalSize]; 
-		PixelDataPtr dst(new PixelData(width, height, depth, getFormat(), buffer, true));
-
-		PixelData myData = lock(HBL_READ_ONLY, mip, face);
-
-#if CM_DEBUG_MODE
-		if(dst->getConsecutiveSize() != myData.getConsecutiveSize())
-		{
-			unlock();
-			CM_EXCEPT(InternalErrorException, "Buffer sizes don't match");
-		}
-#endif
-
-		memcpy(dst->data, myData.data, dst->getConsecutiveSize());
-		unlock();
-
-		op.completeOperation(dst);
-	}
-
-	void D3D11Texture::copy_internal(TexturePtr& target)
-	{
-		if (target->getUsage() != this->getUsage() ||
-			target->getTextureType() != this->getTextureType())
-		{
-			CM_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())
-		{
-			CM_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(getNumFaces() != target->getNumFaces())
-		{
-			CM_EXCEPT(InvalidParametersException, "Number of texture faces doesn't match." \
-				" Num faces: " + toString(getNumFaces()) + "/" + toString(target->getNumFaces()));
-		}
-
-		if(getNumMipmaps() != target->getNumMipmaps())
-		{
-			CM_EXCEPT(InvalidParametersException, "Number of mipmaps doesn't match." \
-				" Num mipmaps: " + toString(getNumMipmaps()) + "/" + toString(target->getNumMipmaps()));
-		}
-
-		// get the target
 		D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
 
 		D3D11Device& device = D3D11RenderSystem::getPrimaryDevice();
@@ -146,7 +48,7 @@ namespace CamelotEngine
 		}
 	}
 
-	PixelData D3D11Texture::lock(LockOptions options, UINT32 mipLevel, UINT32 face)
+	PixelData D3D11Texture::lockImpl(LockOptions options, UINT32 mipLevel, UINT32 face)
 	{
 		UINT32 mipWidth = mipLevel >> mWidth;
 		UINT32 mipHeight = mipLevel >> mHeight;
@@ -194,12 +96,17 @@ namespace CamelotEngine
 		return lockedArea;
 	}
 
-	void D3D11Texture::unlock()
+	void D3D11Texture::unlockImpl()
 	{
 		if(mLockedForReading)
 			_unmapstagingbuffer();
 		else
-			_unmap(mTex);
+		{
+			if(mUsage == TU_DYNAMIC)
+				_unmap(mTex);
+			else
+				_unmapstaticbuffer();
+		}
 	}
 
 	void D3D11Texture::initialize_internal()

+ 22 - 6
CamelotD3D9Renderer/Include/CmD3D9Texture.h

@@ -42,12 +42,6 @@ namespace CamelotEngine {
 		/// destructor
 		~D3D9Texture();
 
-		/// overridden from Texture
-		void copy_internal( TexturePtr& target );
-
-		/// @copydoc Texture::getBuffer
-		HardwarePixelBufferPtr getBuffer_internal(UINT32 face, UINT32 mipmap);
-		
 		/// retrieves a pointer to the actual texture
 		IDirect3DBaseTexture9 *getTexture_internal();		
 		/// retrieves a pointer to the normal 1D/2D texture
@@ -113,6 +107,8 @@ namespace CamelotEngine {
 		// Dynamic textures?
 		bool                            mDynamicTextures;
 		
+		HardwarePixelBufferPtr			mLockedBuffer;
+
 		/// Is hardware gamma supported (read)?
 		bool mHwGammaReadSupported;
 		/// Is hardware gamma supported (write)?
@@ -125,6 +121,12 @@ namespace CamelotEngine {
 		/// overriden from Resource
 		void initialize_internal();	
 
+		/// overridden from Texture
+		void copyImpl(TexturePtr& target);
+
+		PixelData lockImpl(LockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
+		void unlockImpl();
+
 		/// internal method, create a blank normal 1D/2D texture		
 		void _createNormTex(IDirect3DDevice9* d3d9Device);
 		/// internal method, create a blank cube texture		
@@ -159,6 +161,20 @@ namespace CamelotEngine {
 		String _getCubeFaceName(unsigned char face) const
 		{ assert(face < 6); return mCubeFaceNames[face]; }
 		
+		/** Return hardware pixel buffer for a surface. This buffer can then
+			be used to copy data from and to a particular level of the texture.
+			@param face 	Face number, in case of a cubemap texture. Must be 0
+							for other types of textures.
+                            For cubemaps, this is one of 
+                            +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
+			@param mipmap	Mipmap level. This goes from 0 for the first, largest
+							mipmap level to getNumMipmaps()-1 for the smallest.
+			@returns	A shared pointer to a hardware pixel buffer
+			@remarks	The buffer is invalidated when the resource is unloaded or destroyed.
+						Do not use it after the lifetime of the containing texture.
+		*/
+		HardwarePixelBufferPtr getBuffer(UINT32 face, UINT32 mipmap);
+
 		/// internal method, create D3D9HardwarePixelBuffers for every face and
 		/// mipmap level. This method must be called after the D3D texture object was created
 		void _createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources);

+ 28 - 2
CamelotD3D9Renderer/Source/CmD3D9Texture.cpp

@@ -80,7 +80,33 @@ namespace CamelotEngine
 		mSurfaceList.clear();		
 	}
 	/****************************************************************************************/
-	void D3D9Texture::copy_internal(TexturePtr& target)
+	PixelData D3D9Texture::lockImpl(LockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		if(mLockedBuffer != nullptr)
+			CM_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
+
+		UINT32 mipWidth = mipLevel >> mWidth;
+		UINT32 mipHeight = mipLevel >> mHeight;
+		UINT32 mipDepth = mipLevel >> mDepth;
+
+		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mFormat);
+
+		mLockedBuffer = getBuffer(face, mipLevel);
+		lockedArea.data = mLockedBuffer->lock(options);
+
+		return lockedArea;
+	}
+	/****************************************************************************************/
+	void D3D9Texture::unlockImpl()
+	{
+		if(mLockedBuffer == nullptr)
+			CM_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
+
+		mLockedBuffer->unlock();
+		mLockedBuffer = nullptr;
+	}
+	/****************************************************************************************/
+	void D3D9Texture::copyImpl(TexturePtr& target)
 	{
 		THROW_IF_NOT_RENDER_THREAD
 
@@ -1025,7 +1051,7 @@ namespace CamelotEngine
 	}
 	#undef GETLEVEL
 	/****************************************************************************************/
-	HardwarePixelBufferPtr D3D9Texture::getBuffer_internal(UINT32 face, UINT32 mipmap) 
+	HardwarePixelBufferPtr D3D9Texture::getBuffer(UINT32 face, UINT32 mipmap) 
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 

+ 20 - 3
CamelotGLRenderer/Include/CmGLTexture.h

@@ -42,9 +42,6 @@ namespace CamelotEngine {
     public:
         virtual ~GLTexture();      
 
-		/// @copydoc Texture::getBuffer
-		HardwarePixelBufferPtr getBuffer_internal(UINT32 face, UINT32 mipmap);
-
         // Takes the OGRE texture type (1d/2d/3d/cube) and returns the appropriate GL one
         GLenum getGLTextureTarget_internal(void) const;
 
@@ -60,6 +57,11 @@ namespace CamelotEngine {
 
 		void initialize_internal();
 
+		PixelData lockImpl(LockOptions options, UINT32 mipLevel, UINT32 face);
+		void unlockImpl();
+
+		void copyImpl(TexturePtr& target);
+
 		/// @copydoc Texture::createInternalResourcesImpl
 		void createInternalResourcesImpl(void);
         /// @copydoc Resource::freeInternalResourcesImpl
@@ -74,9 +76,24 @@ namespace CamelotEngine {
 
 		void createRenderTexture();
 
+		/** Return hardware pixel buffer for a surface. This buffer can then
+			be used to copy data from and to a particular level of the texture.
+			@param face 	Face number, in case of a cubemap texture. Must be 0
+							for other types of textures.
+                            For cubemaps, this is one of 
+                            +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
+			@param mipmap	Mipmap level. This goes from 0 for the first, largest
+							mipmap level to getNumMipmaps()-1 for the smallest.
+			@returns	A shared pointer to a hardware pixel buffer
+			@remarks	The buffer is invalidated when the resource is unloaded or destroyed.
+						Do not use it after the lifetime of the containing texture.
+		*/
+		HardwarePixelBufferPtr getBuffer(UINT32 face, UINT32 mipmap);
+
     private:
         GLuint mTextureID;
         GLSupport& mGLSupport;
+		HardwarePixelBufferPtr mLockedBuffer;
 		
 		/// Vector of pointers to subsurfaces
 		typedef vector<HardwarePixelBufferPtr>::type SurfaceList;

+ 42 - 2
CamelotGLRenderer/Source/CmGLTexture.cpp

@@ -107,6 +107,46 @@ namespace CamelotEngine {
 	}
 
 	//* Creation / loading methods ********************************************
+	PixelData GLTexture::lockImpl(LockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		if(mLockedBuffer != nullptr)
+			CM_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
+
+		UINT32 mipWidth = mipLevel >> mWidth;
+		UINT32 mipHeight = mipLevel >> mHeight;
+		UINT32 mipDepth = mipLevel >> mDepth;
+
+		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mFormat);
+
+		mLockedBuffer = getBuffer(face, mipLevel);
+		lockedArea.data = mLockedBuffer->lock(options);
+
+		return lockedArea;
+	}
+	/****************************************************************************************/
+	void GLTexture::unlockImpl()
+	{
+		if(mLockedBuffer == nullptr)
+			CM_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
+
+		mLockedBuffer->unlock();
+		mLockedBuffer = nullptr;
+	}
+	/****************************************************************************************/ 
+	void GLTexture::copyImpl(TexturePtr& target)
+	{
+		size_t numMips = std::min(getNumMipmaps(), target->getNumMipmaps());
+
+		GLTexture* glTexture = static_cast<GLTexture*>(target.get());
+		for(unsigned int face=0; face<getNumFaces(); face++)
+		{
+			for(unsigned int mip=0; mip<=numMips; mip++)
+			{
+				glTexture->getBuffer(face, mip)->blit(getBuffer(face, mip));
+			}
+		}
+	}
+	/****************************************************************************************/
 	void GLTexture::createInternalResourcesImpl(void)
     {
 		if (!GLEW_VERSION_1_2 && mTextureType == TEX_TYPE_3D)
@@ -236,7 +276,7 @@ namespace CamelotEngine {
 		}
 		createSurfaceList();
 		// Get final internal format
-		mFormat = getBuffer_internal(0,0)->getFormat();
+		mFormat = getBuffer(0,0)->getFormat();
 	}
 	
     void GLTexture::createRenderTexture(void)
@@ -281,7 +321,7 @@ namespace CamelotEngine {
 	}
 	
 	//---------------------------------------------------------------------------------------------
-	HardwarePixelBufferPtr GLTexture::getBuffer_internal(UINT32 face, UINT32 mipmap)
+	HardwarePixelBufferPtr GLTexture::getBuffer(UINT32 face, UINT32 mipmap)
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 

+ 10 - 16
CamelotRenderer/Include/CmTexture.h

@@ -137,20 +137,6 @@ namespace CamelotEngine {
         */
         virtual UINT32 getNumFaces() const;
 
-		/** Return hardware pixel buffer for a surface. This buffer can then
-			be used to copy data from and to a particular level of the texture.
-			@param face 	Face number, in case of a cubemap texture. Must be 0
-							for other types of textures.
-                            For cubemaps, this is one of 
-                            +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
-			@param mipmap	Mipmap level. This goes from 0 for the first, largest
-							mipmap level to getNumMipmaps()-1 for the smallest.
-			@returns	A shared pointer to a hardware pixel buffer
-			@remarks	The buffer is invalidated when the resource is unloaded or destroyed.
-						Do not use it after the lifetime of the containing texture.
-		*/
-		virtual HardwarePixelBufferPtr getBuffer_internal(UINT32 face=0, UINT32 mipmap=0) = 0;
-		
 		/** Retrieve a platform or API-specific piece of information from this texture.
 		 This method of retrieving information should only be used if you know what you're doing.
 		 @param name The name of the attribute to retrieve
@@ -213,9 +199,12 @@ namespace CamelotEngine {
 		 */
 		virtual void getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op);
 
-		/** Copies (and maybe scales to fit) the contents of this texture to
+		PixelData lock(LockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
+		void unlock();
+
+		/** Copies the contents of this texture to
 			another texture. */
-		virtual void copy_internal(TexturePtr& target);
+		void copy(TexturePtr& target);
 
     protected:
 		friend class TextureManager;
@@ -249,6 +238,11 @@ namespace CamelotEngine {
 		 */
 		virtual void initialize_internal() = 0;
 
+		virtual PixelData lockImpl(LockOptions options, UINT32 mipLevel = 0, UINT32 face = 0) = 0;
+		virtual void unlockImpl() = 0;
+
+		virtual void copyImpl(TexturePtr& target) = 0;
+
 		/// @copydoc Resource::calculateSize
 		UINT32 calculateSize(void) const;
 

+ 66 - 51
CamelotRenderer/Source/CmTexture.cpp

@@ -118,26 +118,9 @@ namespace CamelotEngine {
 
 	void Texture::setRawPixels_internal(const PixelData& data, UINT32 face, UINT32 mip)
 	{
-		THROW_IF_NOT_RENDER_THREAD
-
-		if(mip < 0 || mip > mNumMipmaps)
-			CM_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mip) + ". Min is 0, max is " + toString(mNumMipmaps));
-
-		if(face < 0 || face > getNumFaces())
-			CM_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(getNumFaces()));
-
-		if(mFormat != data.format)
-			CM_EXCEPT(InvalidParametersException, "Provided PixelData has invalid format. Needed: " + toString(mFormat) + ". Got: " + toString(data.format));
-
-		if(mWidth != data.getWidth() || mHeight != data.getHeight() || mDepth != data.getDepth())
-		{
-			CM_EXCEPT(InvalidParametersException, "Provided PixelData size doesn't match the texture size." \
-				" Width: " + toString(mWidth) + "/" + toString(data.getWidth()) + 
-				" Height: " + toString(mHeight) + "/" + toString(data.getHeight()) + 
-				" Depth: " + toString(mDepth) + "/" + toString(data.getDepth()));
-		}
-
-		getBuffer_internal(face, mip)->blitFromMemory(data);
+		PixelData myData = lock(HBL_WRITE_ONLY_DISCARD, mip, face);
+		memcpy(myData.data, data.data, data.getConsecutiveSize());
+		unlock();
 	}
 
 	PixelDataPtr Texture::getRawPixels(UINT32 face, UINT32 mip)
@@ -154,14 +137,6 @@ namespace CamelotEngine {
 
 	void Texture::getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op)
 	{
-		THROW_IF_NOT_RENDER_THREAD;
-
-		if(mip < 0 || mip > mNumMipmaps)
-			CM_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mip) + ". Min is 0, max is " + toString(mNumMipmaps));
-
-		if(face < 0 || mip > getNumFaces())
-			CM_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(getNumFaces()));
-
 		UINT32 numMips = getNumMipmaps();
 
 		UINT32 totalSize = 0;
@@ -179,11 +154,71 @@ namespace CamelotEngine {
 		}
 
 		UINT8* buffer = new UINT8[totalSize]; 
-		PixelDataPtr src(new PixelData(width, height, depth, getFormat(), buffer, true));
+		PixelDataPtr dst(new PixelData(width, height, depth, getFormat(), buffer, true));
+
+		PixelData myData = lock(HBL_READ_ONLY, mip, face);
+
+#if CM_DEBUG_MODE
+		if(dst->getConsecutiveSize() != myData.getConsecutiveSize())
+		{
+			unlock();
+			CM_EXCEPT(InternalErrorException, "Buffer sizes don't match");
+		}
+#endif
+
+		memcpy(dst->data, myData.data, dst->getConsecutiveSize());
+		unlock();
+
+		op.completeOperation(dst);
+	}
+	//----------------------------------------------------------------------------
+	PixelData Texture::lock(LockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		THROW_IF_NOT_RENDER_THREAD;
 
-		getBuffer_internal(face, mip)->blitToMemory(*src);
+		if(mipLevel < 0 || mipLevel > mNumMipmaps)
+			CM_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mipLevel) + ". Min is 0, max is " + toString(getNumMipmaps()));
 
-		op.completeOperation(src);
+		if(face < 0 || face >= getNumFaces())
+			CM_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(getNumFaces()));
+
+		return lockImpl(options, mipLevel, face);
+	}
+	//-----------------------------------------------------------------------------
+	void Texture::unlock()
+	{
+		unlockImpl();
+	}
+	//-----------------------------------------------------------------------------
+	void Texture::copy(TexturePtr& target)
+	{
+		if (target->getUsage() != this->getUsage() ||
+			target->getTextureType() != this->getTextureType())
+		{
+			CM_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())
+		{
+			CM_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(getNumFaces() != target->getNumFaces())
+		{
+			CM_EXCEPT(InvalidParametersException, "Number of texture faces doesn't match." \
+				" Num faces: " + toString(getNumFaces()) + "/" + toString(target->getNumFaces()));
+		}
+
+		if(getNumMipmaps() != target->getNumMipmaps())
+		{
+			CM_EXCEPT(InvalidParametersException, "Number of mipmaps doesn't match." \
+				" Num mipmaps: " + toString(getNumMipmaps()) + "/" + toString(target->getNumMipmaps()));
+		}
+
+		copyImpl(target);
 	}
 	//-----------------------------------------------------------------------------
 	void Texture::unloadImpl(void)
@@ -192,26 +227,6 @@ namespace CamelotEngine {
 
 		freeInternalResources();
 	}
-    //-----------------------------------------------------------------------------   
-    void Texture::copy_internal( TexturePtr& target )
-    {
-		THROW_IF_NOT_RENDER_THREAD;
-
-        if(target->getNumFaces() != getNumFaces())
-        {
-            CM_EXCEPT(InvalidParametersException, 
-                "Texture types must match");
-        }
-
-        size_t numMips = std::min(getNumMipmaps(), target->getNumMipmaps());
-        for(unsigned int face=0; face<getNumFaces(); face++)
-        {
-            for(unsigned int mip=0; mip<=numMips; mip++)
-            {
-                target->getBuffer_internal(face, mip)->blit(getBuffer_internal(face, mip));
-            }
-        }
-    }
 	//----------------------------------------------------------------------------- 
 	void Texture::throwIfNotRenderThread() const
 	{