Browse Source

Modified how textures get locked/unlocked

Marko Pintera 13 years ago
parent
commit
6075746884

+ 49 - 52
CamelotD3D11RenderSystem/Include/CmD3D11Texture.h

@@ -5,77 +5,74 @@
 
 
 namespace CamelotEngine
 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
 		 * @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* _map(ID3D11Resource* res, D3D11_MAP flags, UINT32 mipLevel, UINT32 face);
 		void _unmap(ID3D11Resource* res);
 		void _unmap(ID3D11Resource* res);
 
 
 		void* _mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face);
 		void* _mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face);
 		void _unmapstagingbuffer();
 		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
 		 * @brief	Resource::initialize_internal
 		 */
 		 */
-		void initialize_internal();
-
+		void initialize_internal();
+
 		/**
 		/**
 		 * @copydoc Texture::createInternalResourcesImpl
 		 * @copydoc Texture::createInternalResourcesImpl
 		 */
 		 */
-		void createInternalResourcesImpl();
-		
+		void createInternalResourcesImpl();
+		
 		/**
 		/**
 		 * @copydoc Texture::freeInternalResourcesImpl
 		 * @copydoc Texture::freeInternalResourcesImpl
 		 */
 		 */
-		void freeInternalResourcesImpl();
+		void freeInternalResourcesImpl();
 	};
 	};
 }
 }

+ 9 - 102
CamelotD3D11RenderSystem/Source/CmD3D11Texture.cpp

@@ -34,106 +34,8 @@ namespace CamelotEngine
 		freeInternalResources();			
 		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());
 		D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
 
 
 		D3D11Device& device = D3D11RenderSystem::getPrimaryDevice();
 		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 mipWidth = mipLevel >> mWidth;
 		UINT32 mipHeight = mipLevel >> mHeight;
 		UINT32 mipHeight = mipLevel >> mHeight;
@@ -194,12 +96,17 @@ namespace CamelotEngine
 		return lockedArea;
 		return lockedArea;
 	}
 	}
 
 
-	void D3D11Texture::unlock()
+	void D3D11Texture::unlockImpl()
 	{
 	{
 		if(mLockedForReading)
 		if(mLockedForReading)
 			_unmapstagingbuffer();
 			_unmapstagingbuffer();
 		else
 		else
-			_unmap(mTex);
+		{
+			if(mUsage == TU_DYNAMIC)
+				_unmap(mTex);
+			else
+				_unmapstaticbuffer();
+		}
 	}
 	}
 
 
 	void D3D11Texture::initialize_internal()
 	void D3D11Texture::initialize_internal()

+ 22 - 6
CamelotD3D9Renderer/Include/CmD3D9Texture.h

@@ -42,12 +42,6 @@ namespace CamelotEngine {
 		/// destructor
 		/// destructor
 		~D3D9Texture();
 		~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
 		/// retrieves a pointer to the actual texture
 		IDirect3DBaseTexture9 *getTexture_internal();		
 		IDirect3DBaseTexture9 *getTexture_internal();		
 		/// retrieves a pointer to the normal 1D/2D texture
 		/// retrieves a pointer to the normal 1D/2D texture
@@ -113,6 +107,8 @@ namespace CamelotEngine {
 		// Dynamic textures?
 		// Dynamic textures?
 		bool                            mDynamicTextures;
 		bool                            mDynamicTextures;
 		
 		
+		HardwarePixelBufferPtr			mLockedBuffer;
+
 		/// Is hardware gamma supported (read)?
 		/// Is hardware gamma supported (read)?
 		bool mHwGammaReadSupported;
 		bool mHwGammaReadSupported;
 		/// Is hardware gamma supported (write)?
 		/// Is hardware gamma supported (write)?
@@ -125,6 +121,12 @@ namespace CamelotEngine {
 		/// overriden from Resource
 		/// overriden from Resource
 		void initialize_internal();	
 		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		
 		/// internal method, create a blank normal 1D/2D texture		
 		void _createNormTex(IDirect3DDevice9* d3d9Device);
 		void _createNormTex(IDirect3DDevice9* d3d9Device);
 		/// internal method, create a blank cube texture		
 		/// internal method, create a blank cube texture		
@@ -159,6 +161,20 @@ namespace CamelotEngine {
 		String _getCubeFaceName(unsigned char face) const
 		String _getCubeFaceName(unsigned char face) const
 		{ assert(face < 6); return mCubeFaceNames[face]; }
 		{ 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
 		/// internal method, create D3D9HardwarePixelBuffers for every face and
 		/// mipmap level. This method must be called after the D3D texture object was created
 		/// mipmap level. This method must be called after the D3D texture object was created
 		void _createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources);
 		void _createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources);

+ 28 - 2
CamelotD3D9Renderer/Source/CmD3D9Texture.cpp

@@ -80,7 +80,33 @@ namespace CamelotEngine
 		mSurfaceList.clear();		
 		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
 		THROW_IF_NOT_RENDER_THREAD
 
 
@@ -1025,7 +1051,7 @@ namespace CamelotEngine
 	}
 	}
 	#undef GETLEVEL
 	#undef GETLEVEL
 	/****************************************************************************************/
 	/****************************************************************************************/
-	HardwarePixelBufferPtr D3D9Texture::getBuffer_internal(UINT32 face, UINT32 mipmap) 
+	HardwarePixelBufferPtr D3D9Texture::getBuffer(UINT32 face, UINT32 mipmap) 
 	{
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 		THROW_IF_NOT_RENDER_THREAD;
 
 

+ 20 - 3
CamelotGLRenderer/Include/CmGLTexture.h

@@ -42,9 +42,6 @@ namespace CamelotEngine {
     public:
     public:
         virtual ~GLTexture();      
         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
         // Takes the OGRE texture type (1d/2d/3d/cube) and returns the appropriate GL one
         GLenum getGLTextureTarget_internal(void) const;
         GLenum getGLTextureTarget_internal(void) const;
 
 
@@ -60,6 +57,11 @@ namespace CamelotEngine {
 
 
 		void initialize_internal();
 		void initialize_internal();
 
 
+		PixelData lockImpl(LockOptions options, UINT32 mipLevel, UINT32 face);
+		void unlockImpl();
+
+		void copyImpl(TexturePtr& target);
+
 		/// @copydoc Texture::createInternalResourcesImpl
 		/// @copydoc Texture::createInternalResourcesImpl
 		void createInternalResourcesImpl(void);
 		void createInternalResourcesImpl(void);
         /// @copydoc Resource::freeInternalResourcesImpl
         /// @copydoc Resource::freeInternalResourcesImpl
@@ -74,9 +76,24 @@ namespace CamelotEngine {
 
 
 		void createRenderTexture();
 		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:
     private:
         GLuint mTextureID;
         GLuint mTextureID;
         GLSupport& mGLSupport;
         GLSupport& mGLSupport;
+		HardwarePixelBufferPtr mLockedBuffer;
 		
 		
 		/// Vector of pointers to subsurfaces
 		/// Vector of pointers to subsurfaces
 		typedef vector<HardwarePixelBufferPtr>::type SurfaceList;
 		typedef vector<HardwarePixelBufferPtr>::type SurfaceList;

+ 42 - 2
CamelotGLRenderer/Source/CmGLTexture.cpp

@@ -107,6 +107,46 @@ namespace CamelotEngine {
 	}
 	}
 
 
 	//* Creation / loading methods ********************************************
 	//* 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)
 	void GLTexture::createInternalResourcesImpl(void)
     {
     {
 		if (!GLEW_VERSION_1_2 && mTextureType == TEX_TYPE_3D)
 		if (!GLEW_VERSION_1_2 && mTextureType == TEX_TYPE_3D)
@@ -236,7 +276,7 @@ namespace CamelotEngine {
 		}
 		}
 		createSurfaceList();
 		createSurfaceList();
 		// Get final internal format
 		// Get final internal format
-		mFormat = getBuffer_internal(0,0)->getFormat();
+		mFormat = getBuffer(0,0)->getFormat();
 	}
 	}
 	
 	
     void GLTexture::createRenderTexture(void)
     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;
 		THROW_IF_NOT_RENDER_THREAD;
 
 

+ 10 - 16
CamelotRenderer/Include/CmTexture.h

@@ -137,20 +137,6 @@ namespace CamelotEngine {
         */
         */
         virtual UINT32 getNumFaces() const;
         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.
 		/** 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.
 		 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
 		 @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);
 		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. */
 			another texture. */
-		virtual void copy_internal(TexturePtr& target);
+		void copy(TexturePtr& target);
 
 
     protected:
     protected:
 		friend class TextureManager;
 		friend class TextureManager;
@@ -249,6 +238,11 @@ namespace CamelotEngine {
 		 */
 		 */
 		virtual void initialize_internal() = 0;
 		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
 		/// @copydoc Resource::calculateSize
 		UINT32 calculateSize(void) const;
 		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)
 	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)
 	PixelDataPtr Texture::getRawPixels(UINT32 face, UINT32 mip)
@@ -154,14 +137,6 @@ namespace CamelotEngine {
 
 
 	void Texture::getRawPixels_internal(UINT32 face, UINT32 mip, AsyncOp& op)
 	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 numMips = getNumMipmaps();
 
 
 		UINT32 totalSize = 0;
 		UINT32 totalSize = 0;
@@ -179,11 +154,71 @@ namespace CamelotEngine {
 		}
 		}
 
 
 		UINT8* buffer = new UINT8[totalSize]; 
 		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)
 	void Texture::unloadImpl(void)
@@ -192,26 +227,6 @@ namespace CamelotEngine {
 
 
 		freeInternalResources();
 		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
 	void Texture::throwIfNotRenderThread() const
 	{
 	{