Przeglądaj źródła

Default material parameter textures & sampler states are now used whenever the parameter is set to null

BearishSun 10 lat temu
rodzic
commit
af5cd7361f

+ 14 - 0
BansheeCore/Include/BsMaterialParams.h

@@ -342,6 +342,18 @@ namespace BansheeEngine
 		 */
 		 */
 		void setSamplerState(UINT32 index, const SamplerStatePtr& value);
 		void setSamplerState(UINT32 index, const SamplerStatePtr& value);
 
 
+		/** 
+		 * Returns the default texture (one assigned when no other is provided), if available for the specified index. 
+		 * Index is the internal parameter index and the caller must guarantee the index is valid.
+		 */
+		void getDefaultTexture(UINT32 index, HTexture& value) const;
+
+		/** 
+		 * Returns the default sampler state (one assigned when no other is provided), if available for the specified index.
+		 * Index is the internal parameter index and the caller must guarantee the index is valid.
+		 */
+		void getDefaultSamplerState(UINT32 index, SamplerStatePtr& value) const;
+
 	private:
 	private:
 		const static UINT32 STATIC_BUFFER_SIZE = 256;
 		const static UINT32 STATIC_BUFFER_SIZE = 256;
 
 
@@ -351,6 +363,8 @@ namespace BansheeEngine
 		StructParamData* mStructParams = nullptr;
 		StructParamData* mStructParams = nullptr;
 		TextureParamData* mTextureParams = nullptr;
 		TextureParamData* mTextureParams = nullptr;
 		SamplerStatePtr* mSamplerStateParams = nullptr;
 		SamplerStatePtr* mSamplerStateParams = nullptr;
+		HTexture* mDefaultTextureParams = nullptr;
+		SamplerStatePtr* mDefaultSamplerStateParams = nullptr;
 
 
 		UINT32 mDataSize = 0;
 		UINT32 mDataSize = 0;
 		UINT32 mNumStructParams = 0;
 		UINT32 mNumStructParams = 0;

+ 8 - 2
BansheeCore/Include/BsShaderRTTI.h

@@ -30,6 +30,7 @@ namespace BansheeEngine
 			memory = rttiWriteElem(data.name, memory);
 			memory = rttiWriteElem(data.name, memory);
 			memory = rttiWriteElem(data.gpuVariableName, memory);
 			memory = rttiWriteElem(data.gpuVariableName, memory);
 			memory = rttiWriteElem(data.elementSize, memory);
 			memory = rttiWriteElem(data.elementSize, memory);
+			memory = rttiWriteElem(data.defaultValueIdx, memory);
 		}
 		}
 
 
 		static UINT32 fromMemory(SHADER_DATA_PARAM_DESC& data, char* memory)
 		static UINT32 fromMemory(SHADER_DATA_PARAM_DESC& data, char* memory)
@@ -44,6 +45,7 @@ namespace BansheeEngine
 			memory = rttiReadElem(data.name, memory);
 			memory = rttiReadElem(data.name, memory);
 			memory = rttiReadElem(data.gpuVariableName, memory);
 			memory = rttiReadElem(data.gpuVariableName, memory);
 			memory = rttiReadElem(data.elementSize, memory);
 			memory = rttiReadElem(data.elementSize, memory);
+			memory = rttiReadElem(data.defaultValueIdx, memory);
 
 
 			return size;
 			return size;
 		}
 		}
@@ -51,7 +53,8 @@ namespace BansheeEngine
 		static UINT32 getDynamicSize(const SHADER_DATA_PARAM_DESC& data)	
 		static UINT32 getDynamicSize(const SHADER_DATA_PARAM_DESC& data)	
 		{ 
 		{ 
 			UINT64 dataSize = rttiGetElemSize(data.arraySize) + rttiGetElemSize(data.rendererSemantic) + rttiGetElemSize(data.type) +
 			UINT64 dataSize = rttiGetElemSize(data.arraySize) + rttiGetElemSize(data.rendererSemantic) + rttiGetElemSize(data.type) +
-				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableName) + rttiGetElemSize(data.elementSize) + sizeof(UINT32);
+				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableName) + rttiGetElemSize(data.elementSize) + 
+				rttiGetElemSize(data.defaultValueIdx) + sizeof(UINT32);
 
 
 #if BS_DEBUG_MODE
 #if BS_DEBUG_MODE
 			if(dataSize > std::numeric_limits<UINT32>::max())
 			if(dataSize > std::numeric_limits<UINT32>::max())
@@ -80,6 +83,7 @@ namespace BansheeEngine
 			memory = rttiWriteElem(data.type, memory);
 			memory = rttiWriteElem(data.type, memory);
 			memory = rttiWriteElem(data.name, memory);
 			memory = rttiWriteElem(data.name, memory);
 			memory = rttiWriteElem(data.gpuVariableNames, memory);
 			memory = rttiWriteElem(data.gpuVariableNames, memory);
+			memory = rttiWriteElem(data.defaultValueIdx, memory);
 		}
 		}
 
 
 		static UINT32 fromMemory(SHADER_OBJECT_PARAM_DESC& data, char* memory)
 		static UINT32 fromMemory(SHADER_OBJECT_PARAM_DESC& data, char* memory)
@@ -92,6 +96,7 @@ namespace BansheeEngine
 			memory = rttiReadElem(data.type, memory);
 			memory = rttiReadElem(data.type, memory);
 			memory = rttiReadElem(data.name, memory);
 			memory = rttiReadElem(data.name, memory);
 			memory = rttiReadElem(data.gpuVariableNames, memory);
 			memory = rttiReadElem(data.gpuVariableNames, memory);
+			memory = rttiReadElem(data.defaultValueIdx, memory);
 
 
 			return size;
 			return size;
 		}
 		}
@@ -99,7 +104,8 @@ namespace BansheeEngine
 		static UINT32 getDynamicSize(const SHADER_OBJECT_PARAM_DESC& data)	
 		static UINT32 getDynamicSize(const SHADER_OBJECT_PARAM_DESC& data)	
 		{ 
 		{ 
 			UINT64 dataSize = rttiGetElemSize(data.rendererSemantic) + rttiGetElemSize(data.type) +
 			UINT64 dataSize = rttiGetElemSize(data.rendererSemantic) + rttiGetElemSize(data.type) +
-				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableNames) + sizeof(UINT32);
+				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableNames) + 
+				rttiGetElemSize(data.defaultValueIdx) + sizeof(UINT32);
 
 
 #if BS_DEBUG_MODE
 #if BS_DEBUG_MODE
 			if(dataSize > std::numeric_limits<UINT32>::max())
 			if(dataSize > std::numeric_limits<UINT32>::max())

+ 7 - 0
BansheeCore/Include/BsTexture.h

@@ -415,6 +415,13 @@ namespace BansheeEngine
 		static TexturePtr _createPtr(TextureType texType, UINT32 width, UINT32 height, int num_mips,
 		static TexturePtr _createPtr(TextureType texType, UINT32 width, UINT32 height, int num_mips,
 			PixelFormat format, int usage = TU_DEFAULT, bool hwGammaCorrection = false, UINT32 multisampleCount = 0);
 			PixelFormat format, int usage = TU_DEFAULT, bool hwGammaCorrection = false, UINT32 multisampleCount = 0);
 
 
+		/**
+		 * @copydoc	create(const PixelDataPtr&, int, bool)
+		 *
+		 * @note	Internal method. Creates a texture pointer without a handle. Use create() for normal usage.
+		 */
+		static TexturePtr _createPtr(const PixelDataPtr& pixelData, int usage = TU_DEFAULT, bool hwGammaCorrection = false);
+
     protected:
     protected:
 		friend class TextureManager;
 		friend class TextureManager;
 
 

+ 0 - 15
BansheeCore/Source/BsMaterial.cpp

@@ -1212,21 +1212,6 @@ namespace BansheeEngine
 	{
 	{
 		if (mShader != nullptr)
 		if (mShader != nullptr)
 			dependencies.push_back(mShader);
 			dependencies.push_back(mShader);
-
-		if (mShader.isLoaded())
-		{
-			const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams = mShader->getTextureParams();
-
-			for (auto& param : textureParams)
-			{
-				if (param.second.defaultValueIdx != (UINT32)-1)
-				{
-					HTexture defaultTex = mShader->getDefaultTexture(param.second.defaultValueIdx);
-					if (defaultTex != nullptr)
-						dependencies.push_back(defaultTex);
-				}
-			}
-		}
 	}
 	}
 
 
 	void Material::initializeIfLoaded()
 	void Material::initializeIfLoaded()

+ 14 - 4
BansheeCore/Source/BsMaterialParam.cpp

@@ -194,12 +194,17 @@ namespace BansheeEngine
 		if (mMaterialParams == nullptr)
 		if (mMaterialParams == nullptr)
 			return;
 			return;
 
 
-		mMaterialParams->setTexture(mParamIndex, texture);
+		// If there is a default value, assign that instead of null
+		HTexture newValue = texture;
+		if (newValue == nullptr)
+			mMaterialParams->getDefaultTexture(mParamIndex, newValue);
+
+		mMaterialParams->setTexture(mParamIndex, newValue);
 
 
 		if (mGPUParams != nullptr)
 		if (mGPUParams != nullptr)
 		{
 		{
 			for (auto& param : *mGPUParams)
 			for (auto& param : *mGPUParams)
-				param.set(texture);
+				param.set(newValue);
 		}
 		}
 	}
 	}
 
 
@@ -325,12 +330,17 @@ namespace BansheeEngine
 		if (mMaterialParams == nullptr)
 		if (mMaterialParams == nullptr)
 			return;
 			return;
 
 
-		mMaterialParams->setSamplerState(mParamIndex, sampState);
+		// If there is a default value, assign that instead of null
+		SPtr<SamplerState> newValue = sampState;
+		if (newValue == nullptr)
+			mMaterialParams->getDefaultSamplerState(mParamIndex, newValue);
+
+		mMaterialParams->setSamplerState(mParamIndex, newValue);
 
 
 		if (mGPUParams != nullptr)
 		if (mGPUParams != nullptr)
 		{
 		{
 			for (auto& param : *mGPUParams)
 			for (auto& param : *mGPUParams)
-				param.set(sampState);
+				param.set(newValue);
 		}
 		}
 	}
 	}
 
 

+ 24 - 0
BansheeCore/Source/BsMaterialParams.cpp

@@ -34,6 +34,8 @@ namespace BansheeEngine
 		mStructParams = mAlloc.construct<StructParamData>(mNumStructParams);
 		mStructParams = mAlloc.construct<StructParamData>(mNumStructParams);
 		mTextureParams = mAlloc.construct<TextureParamData>(mNumTextureParams);
 		mTextureParams = mAlloc.construct<TextureParamData>(mNumTextureParams);
 		mSamplerStateParams = mAlloc.construct<SamplerStatePtr>(mNumSamplerParams);
 		mSamplerStateParams = mAlloc.construct<SamplerStatePtr>(mNumSamplerParams);
+		mDefaultTextureParams = mAlloc.construct<HTexture>(mNumTextureParams);
+		mDefaultSamplerStateParams = mAlloc.construct<SamplerStatePtr>(mNumSamplerParams);
 
 
 		UINT32 mDataBufferIdx = 0;
 		UINT32 mDataBufferIdx = 0;
 		UINT32 mStructIdx = 0;
 		UINT32 mStructIdx = 0;
@@ -81,6 +83,9 @@ namespace BansheeEngine
 			TextureParamData& param = mTextureParams[mTextureIdx];
 			TextureParamData& param = mTextureParams[mTextureIdx];
 			param.isLoadStore = false;
 			param.isLoadStore = false;
 
 
+			if (entry.second.defaultValueIdx != (UINT32)-1)
+				mDefaultTextureParams[mTextureIdx] = shader->getDefaultTexture(entry.second.defaultValueIdx);
+
 			mTextureIdx++;
 			mTextureIdx++;
 		}
 		}
 
 
@@ -93,6 +98,9 @@ namespace BansheeEngine
 			dataParam.dataType = GPDT_UNKNOWN;
 			dataParam.dataType = GPDT_UNKNOWN;
 			dataParam.index = mSamplerIdx;
 			dataParam.index = mSamplerIdx;
 
 
+			if (entry.second.defaultValueIdx != (UINT32)-1)
+				mDefaultSamplerStateParams[mTextureIdx] = shader->getDefaultSampler(entry.second.defaultValueIdx);
+
 			mSamplerIdx++;
 			mSamplerIdx++;
 		}
 		}
 
 
@@ -112,6 +120,12 @@ namespace BansheeEngine
 		mAlloc.destruct(mTextureParams, mNumTextureParams);
 		mAlloc.destruct(mTextureParams, mNumTextureParams);
 		mAlloc.destruct(mSamplerStateParams, mNumSamplerParams);
 		mAlloc.destruct(mSamplerStateParams, mNumSamplerParams);
 
 
+		if(mDefaultTextureParams != nullptr)
+			mAlloc.destruct(mDefaultTextureParams, mNumTextureParams);
+
+		if (mDefaultSamplerStateParams != nullptr)
+			mAlloc.destruct(mDefaultSamplerStateParams, mNumSamplerParams);
+
 		mAlloc.clear();
 		mAlloc.clear();
 	}
 	}
 
 
@@ -329,6 +343,16 @@ namespace BansheeEngine
 		mSamplerStateParams[index] = value;
 		mSamplerStateParams[index] = value;
 	}
 	}
 
 
+	void MaterialParams::getDefaultTexture(UINT32 index, HTexture& value) const
+	{
+		value = mDefaultTextureParams[index];
+	}
+
+	void MaterialParams::getDefaultSamplerState(UINT32 index, SamplerStatePtr& value) const
+	{
+		value = mDefaultSamplerStateParams[index];
+	}
+
 	RTTITypeBase* MaterialParams::TextureParamData::getRTTIStatic()
 	RTTITypeBase* MaterialParams::TextureParamData::getRTTIStatic()
 	{
 	{
 		return TextureParamDataRTTI::instance();
 		return TextureParamDataRTTI::instance();

+ 542 - 537
BansheeCore/Source/BsTexture.cpp

@@ -1,538 +1,543 @@
-#include "BsPixelBuffer.h"
-#include "BsTexture.h"
-#include "BsTextureRTTI.h"
-#include "BsDataStream.h"
-#include "BsException.h"
-#include "BsDebug.h"
-#include "BsCoreThread.h"
-#include "BsAsyncOp.h"
-#include "BsResources.h"
-#include "BsPixelUtil.h"
-
-namespace BansheeEngine 
-{
-	TextureProperties::TextureProperties()
-		:mHeight(32), mWidth(32), mDepth(1), mNumMipmaps(0),
-		mHwGamma(false), mMultisampleCount(0), mTextureType(TEX_TYPE_2D),
-		mFormat(PF_UNKNOWN), mUsage(TU_DEFAULT)
-	{
-
-	}
-
-	TextureProperties::TextureProperties(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
-		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount)
-		:mHeight(height), mWidth(width), mDepth(depth), mNumMipmaps(numMipmaps),
-		mHwGamma(hwGamma), mMultisampleCount(multisampleCount), mTextureType(textureType),
-		mFormat(format), mUsage(usage)
-	{
-
-	}
-
-	bool TextureProperties::hasAlpha() const
-	{
-		return PixelUtil::hasAlpha(mFormat);
-	}
-
-	UINT32 TextureProperties::getNumFaces() const
-	{
-		return getTextureType() == TEX_TYPE_CUBE_MAP ? 6 : 1;
-	}
-
-	void TextureProperties::mapFromSubresourceIdx(UINT32 subresourceIdx, UINT32& face, UINT32& mip) const
-	{
-		UINT32 numMipmaps = getNumMipmaps() + 1;
-
-		face = Math::floorToInt((subresourceIdx) / (float)numMipmaps);
-		mip = subresourceIdx % numMipmaps;
-	}
-
-	UINT32 TextureProperties::mapToSubresourceIdx(UINT32 face, UINT32 mip) const
-	{
-		return face * (getNumMipmaps() + 1) + mip;
-	}
-
-	PixelDataPtr TextureProperties::allocateSubresourceBuffer(UINT32 subresourceIdx) const
-	{
-		UINT32 face = 0;
-		UINT32 mip = 0;
-		mapFromSubresourceIdx(subresourceIdx, face, mip);
-
-		UINT32 numMips = getNumMipmaps();
-		UINT32 width = getWidth();
-		UINT32 height = getHeight();
-		UINT32 depth = getDepth();
-
-		UINT32 totalSize = PixelUtil::getMemorySize(width, height, depth, getFormat());
-
-		for (UINT32 j = 0; j < mip; j++)
-		{
-			totalSize = PixelUtil::getMemorySize(width, height, depth, getFormat());
-
-			if (width != 1) width /= 2;
-			if (height != 1) height /= 2;
-			if (depth != 1) depth /= 2;
-		}
-
-		PixelDataPtr dst = bs_shared_ptr_new<PixelData>(width, height, depth, getFormat());
-
-		dst->allocateInternalBuffer();
-
-		return dst;
-	}
-
-	TextureCore::TextureCore(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
-		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initData)
-		:mProperties(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount), 
-		mInitData(initData)
-	{ }
-
-	void TextureCore::initialize()
-	{
-		if (mInitData != nullptr)
-		{
-			writeSubresource(0, *mInitData, true);
-			mInitData->_unlock();
-			mInitData = nullptr;
-		}
-	}
-
-	void TextureCore::writeSubresource(UINT32 subresourceIdx, const PixelData& pixelData, bool discardEntireBuffer)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if(discardEntireBuffer)
-		{
-			if(mProperties.getUsage() != TU_DYNAMIC)
-			{
-				// Buffer discard is enabled but buffer was not created as dynamic. Disabling discard.
-				discardEntireBuffer = false;
-			}
-		}
-		else
-		{
-			if (mProperties.getUsage() == TU_DYNAMIC)
-			{
-				LOGWRN("Buffer discard is not enabled but buffer was not created as dynamic. Enabling discard.");
-				discardEntireBuffer = true;
-			}
-		}
-
-		UINT32 face = 0;
-		UINT32 mip = 0;
-		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mip);
-
-		writeData(pixelData, mip, face, discardEntireBuffer);
-	}
-
-	void TextureCore::readSubresource(UINT32 subresourceIdx, PixelData& data)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		UINT32 face = 0;
-		UINT32 mip = 0;
-		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mip);
-
-		PixelData& pixelData = static_cast<PixelData&>(data);
-
-		UINT32 mipWidth, mipHeight, mipDepth;
-		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
-			mip, mipWidth, mipHeight, mipDepth);
-
-		if (pixelData.getWidth() != mipWidth || pixelData.getHeight() != mipHeight ||
-			pixelData.getDepth() != mipDepth || pixelData.getFormat() != mProperties.getFormat())
-		{
-			BS_EXCEPT(RenderingAPIException, "Provided buffer is not of valid dimensions or format in order to read from this texture.");
-		}
-
-		readData(pixelData, mip, face);
-	}
-
-	PixelData TextureCore::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if (mipLevel < 0 || mipLevel > mProperties.getNumMipmaps())
-			BS_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mipLevel) + ". Min is 0, max is " + toString(mProperties.getNumMipmaps()));
-
-		if (face < 0 || face >= mProperties.getNumFaces())
-			BS_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(mProperties.getNumFaces()));
-
-		return lockImpl(options, mipLevel, face);
-	}
-
-	void TextureCore::unlock()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		unlockImpl();
-	}
-
-	void TextureCore::copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if (target->mProperties.getTextureType() != mProperties.getTextureType())
-			BS_EXCEPT(InvalidParametersException, "Source and destination textures must be of same type and must have the same usage and type.");
-
-		if (mProperties.getFormat() != target->mProperties.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 (target->mProperties.getMultisampleCount() > 0 && mProperties.getMultisampleCount() != target->mProperties.getMultisampleCount())
-			BS_EXCEPT(InvalidParametersException, "When copying to a multisampled texture, source texture must have the same number of samples.");
-
-		UINT32 srcFace = 0;
-		UINT32 srcMipLevel = 0;
-
-		UINT32 destFace = 0;
-		UINT32 destMipLevel = 0;
-
-		mProperties.mapFromSubresourceIdx(srcSubresourceIdx, srcFace, srcMipLevel);
-		target->mProperties.mapFromSubresourceIdx(destSubresourceIdx, destFace, destMipLevel);
-
-		if (destFace >= mProperties.getNumFaces())
-			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
-
-		if (srcFace >= target->mProperties.getNumFaces())
-			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
-
-		if (srcMipLevel > mProperties.getNumMipmaps())
-			BS_EXCEPT(InvalidParametersException, "Source mip level out of range. Valid range is [0, " + toString(mProperties.getNumMipmaps()) + "]");
-
-		if (destMipLevel > target->mProperties.getNumMipmaps())
-			BS_EXCEPT(InvalidParametersException, "Destination mip level out of range. Valid range is [0, " + toString(target->mProperties.getNumMipmaps()) + "]");
-
-		UINT32 srcMipWidth = mProperties.getWidth() >> srcMipLevel;
-		UINT32 srcMipHeight = mProperties.getHeight() >> srcMipLevel;
-		UINT32 srcMipDepth = mProperties.getDepth() >> srcMipLevel;
-
-		UINT32 dstMipWidth = target->mProperties.getWidth() >> destMipLevel;
-		UINT32 dstMipHeight = target->mProperties.getHeight() >> destMipLevel;
-		UINT32 dstMipDepth = target->mProperties.getDepth() >> destMipLevel;
-
-		if (srcMipWidth != dstMipWidth || srcMipHeight != dstMipHeight || srcMipDepth != dstMipDepth)
-			BS_EXCEPT(InvalidParametersException, "Source and destination sizes must match");
-
-		copyImpl(srcFace, srcMipLevel, destFace, destMipLevel, target);
-	}
-
-	/************************************************************************/
-	/* 								TEXTURE VIEW                      		*/
-	/************************************************************************/
-
-	TextureViewPtr TextureCore::createView(const SPtr<TextureCore>& texture, const TEXTURE_VIEW_DESC& desc)
-	{
-		return bs_shared_ptr<TextureView>(new (bs_alloc<TextureView>()) TextureView(texture, desc));
-	}
-
-	void TextureCore::clearBufferViews()
-	{
-		mTextureViews.clear();
-	}
-
-	TextureViewPtr TextureCore::requestView(const SPtr<TextureCore>& texture, UINT32 mostDetailMip, UINT32 numMips, UINT32 firstArraySlice, UINT32 numArraySlices, GpuViewUsage usage)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		assert(texture != nullptr);
-
-		TEXTURE_VIEW_DESC key;
-		key.mostDetailMip = mostDetailMip;
-		key.numMips = numMips;
-		key.firstArraySlice = firstArraySlice;
-		key.numArraySlices = numArraySlices;
-		key.usage = usage;
-
-		auto iterFind = texture->mTextureViews.find(key);
-		if (iterFind == texture->mTextureViews.end())
-		{
-			TextureViewPtr newView = texture->createView(texture, key);
-			texture->mTextureViews[key] = new (bs_alloc<TextureViewReference>()) TextureViewReference(newView);
-
-			iterFind = texture->mTextureViews.find(key);
-		}
-
-		iterFind->second->refCount++;
-		return iterFind->second->view;
-	}
-
-	void TextureCore::releaseView(const TextureViewPtr& view)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		assert(view != nullptr);
-
-		SPtr<TextureCore> texture = view->getTexture();
-
-		auto iterFind = texture->mTextureViews.find(view->getDesc());
-		if (iterFind == texture->mTextureViews.end())
-		{
-			BS_EXCEPT(InternalErrorException, "Trying to release a texture view that doesn't exist!");
-		}
-
-		iterFind->second->refCount--;
-
-		if (iterFind->second->refCount == 0)
-		{
-			TextureViewReference* toRemove = iterFind->second;
-
-			texture->mTextureViews.erase(iterFind);
-
-			bs_delete(toRemove);
-		}
-	}
-
-	Texture::Texture()
-	{
-
-	}
-
-	Texture::Texture(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
-		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount)
-		:mProperties(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount)
-    {
-        
-    }
-
-	Texture::Texture(const PixelDataPtr& pixelData, int usage, bool hwGamma)
-		: mProperties(pixelData->getDepth() > 1 ? TEX_TYPE_3D : TEX_TYPE_2D, pixelData->getWidth(), pixelData->getHeight(),
-		pixelData->getDepth(), 0, pixelData->getFormat(), usage, hwGamma, 0), mInitData(pixelData)
-	{
-		if (mInitData != nullptr)
-			mInitData->_lock();
-	}
-
-	void Texture::initialize()
-	{
-		mSize = calculateSize();
-
-		// Allocate CPU buffers if needed
-		if ((mProperties.getUsage() & TU_CPUCACHED) != 0)
-		{
-			createCPUBuffers();
-
-			if (mInitData != nullptr)
-				updateCPUBuffers(0, *mInitData);
-		}
-
-		Resource::initialize();
-	}
-
-	SPtr<CoreObjectCore> Texture::createCore() const
-	{
-		const TextureProperties& props = getProperties();
-
-		SPtr<CoreObjectCore> coreObj = TextureCoreManager::instance().createTextureInternal(props.getTextureType(), props.getWidth(), props.getHeight(),
-			props.getDepth(), props.getNumMipmaps(), props.getFormat(), props.getUsage(), props.isHardwareGammaEnabled(), props.getMultisampleCount(), mInitData);
-
-		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
-			mInitData = nullptr;
-
-		return coreObj;
-	}
-
-	AsyncOp Texture::writeSubresource(CoreAccessor& accessor, UINT32 subresourceIdx, const PixelDataPtr& data, bool discardEntireBuffer)
-	{
-		updateCPUBuffers(subresourceIdx, *data);
-
-		data->_lock();
-
-		std::function<void(const SPtr<TextureCore>&, UINT32, const PixelDataPtr&, bool, AsyncOp&)> func =
-			[&](const SPtr<TextureCore>& texture, UINT32 _subresourceIdx, const PixelDataPtr& _pixData, bool _discardEntireBuffer, AsyncOp& asyncOp)
-		{
-			texture->writeSubresource(_subresourceIdx, *_pixData, _discardEntireBuffer);
-			_pixData->_unlock();
-			asyncOp._completeOperation();
-
-		};
-
-		return accessor.queueReturnCommand(std::bind(func, getCore(), subresourceIdx,
-			data, discardEntireBuffer, std::placeholders::_1));
-	}
-
-	AsyncOp Texture::readSubresource(CoreAccessor& accessor, UINT32 subresourceIdx, const PixelDataPtr& data)
-	{
-		data->_lock();
-
-		std::function<void(const SPtr<TextureCore>&, UINT32, const PixelDataPtr&, AsyncOp&)> func =
-			[&](const SPtr<TextureCore>& texture, UINT32 _subresourceIdx, const PixelDataPtr& _pixData, AsyncOp& asyncOp)
-		{
-			texture->readSubresource(_subresourceIdx, *_pixData);
-			_pixData->_unlock();
-			asyncOp._completeOperation();
-
-		};
-
-		return accessor.queueReturnCommand(std::bind(func, getCore(), subresourceIdx,
-			data, std::placeholders::_1));
-	}
-
-	UINT32 Texture::calculateSize() const
-	{
-		return mProperties.getNumFaces() * PixelUtil::getMemorySize(mProperties.getWidth(),
-			mProperties.getHeight(), mProperties.getDepth(), mProperties.getFormat());
-	}
-
-	void Texture::updateCPUBuffers(UINT32 subresourceIdx, const PixelData& pixelData)
-	{
-		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
-			return;
-
-		if (subresourceIdx >= (UINT32)mCPUSubresourceData.size())
-		{
-			LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. " + toString(mCPUSubresourceData.size()));
-			return;
-		}
-
-		UINT32 mipLevel;
-		UINT32 face;
-		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mipLevel);
-
-		UINT32 mipWidth, mipHeight, mipDepth;
-		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
-			mipLevel, mipWidth, mipHeight, mipDepth);
-
-		if (pixelData.getWidth() != mipWidth || pixelData.getHeight() != mipHeight ||
-			pixelData.getDepth() != mipDepth || pixelData.getFormat() != mProperties.getFormat())
-		{
-			LOGERR("Provided buffer is not of valid dimensions or format in order to update this texture.");
-			return;
-		}
-
-		if (mCPUSubresourceData[subresourceIdx]->getSize() != pixelData.getSize())
-			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
-
-		UINT8* dest = mCPUSubresourceData[subresourceIdx]->getData();
-		UINT8* src = pixelData.getData();
-
-		memcpy(dest, src, pixelData.getSize());
-	}
-
-	void Texture::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
-	{
-		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
-		{
-			LOGERR("Attempting to read CPU data from a texture that is created without CPU caching.");
-			return;
-		}
-
-		UINT32 mipWidth, mipHeight, mipDepth;
-		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
-			mipLevel, mipWidth, mipHeight, mipDepth);
-
-		if (dest.getWidth() != mipWidth || dest.getHeight() != mipHeight ||
-			dest.getDepth() != mipDepth || dest.getFormat() != mProperties.getFormat())
-		{
-			LOGERR("Provided buffer is not of valid dimensions or format in order to read from this texture.");
-			return;
-		}
-
-		UINT32 subresourceIdx = mProperties.mapToSubresourceIdx(face, mipLevel);
-		if (subresourceIdx >= (UINT32)mCPUSubresourceData.size())
-		{
-			LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. " + toString(mCPUSubresourceData.size()));
-			return;
-		}
-
-		if (mCPUSubresourceData[subresourceIdx]->getSize() != dest.getSize())
-			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
-
-		UINT8* srcPtr = mCPUSubresourceData[subresourceIdx]->getData();
-		UINT8* destPtr = dest.getData();
-
-		memcpy(destPtr, srcPtr, dest.getSize());
-	}
-
-	void Texture::createCPUBuffers()
-	{
-		UINT32 numFaces = mProperties.getNumFaces();
-		UINT32 numMips = mProperties.getNumMipmaps() + 1;
-
-		UINT32 numSubresources = numFaces * numMips;
-		mCPUSubresourceData.resize(numSubresources);
-
-		for (UINT32 i = 0; i < numFaces; i++)
-		{
-			UINT32 curWidth = mProperties.getWidth();
-			UINT32 curHeight = mProperties.getHeight();
-			UINT32 curDepth = mProperties.getDepth();
-
-			for (UINT32 j = 0; j < numMips; j++)
-			{
-				UINT32 subresourceIdx = mProperties.mapToSubresourceIdx(i, j);
-
-				mCPUSubresourceData[subresourceIdx] = bs_shared_ptr_new<PixelData>(curWidth, curHeight, curDepth, mProperties.getFormat());
-				mCPUSubresourceData[subresourceIdx]->allocateInternalBuffer();
-
-				if (curWidth > 1)
-					curWidth = curWidth / 2;
-
-				if (curHeight > 1)
-					curHeight = curHeight / 2;
-
-				if (curDepth > 1)
-					curDepth = curDepth / 2;
-			}
-		}
-	}
-
-	SPtr<TextureCore> Texture::getCore() const
-	{
-		return std::static_pointer_cast<TextureCore>(mCoreSpecific);
-	}
-
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
-
-	RTTITypeBase* Texture::getRTTIStatic()
-	{
-		return TextureRTTI::instance();
-	}
-
-	RTTITypeBase* Texture::getRTTI() const
-	{
-		return Texture::getRTTIStatic();
-	}
-
-	/************************************************************************/
-	/* 								STATICS	                      			*/
-	/************************************************************************/
-	HTexture Texture::create(TextureType texType, UINT32 width, UINT32 height, UINT32 depth, 
-		int numMips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
-	{
-		TexturePtr texturePtr = _createPtr(texType, 
-			width, height, depth, numMips, format, usage, hwGammaCorrection, multisampleCount);
-
-		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
-	}
-	
-	HTexture Texture::create(TextureType texType, UINT32 width, UINT32 height, 
-		int numMips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
-	{
-		TexturePtr texturePtr = _createPtr(texType, 
-			width, height, numMips, format, usage, hwGammaCorrection, multisampleCount);
-
-		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
-	}
-
-	HTexture Texture::create(const PixelDataPtr& pixelData, int usage, bool hwGammaCorrection)
-	{
-		TexturePtr texturePtr = TextureManager::instance().createTexture(pixelData, usage, hwGammaCorrection);
-
-		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
-	}
-
-	TexturePtr Texture::_createPtr(TextureType texType, UINT32 width, UINT32 height, UINT32 depth, 
-		int num_mips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
-	{
-		return TextureManager::instance().createTexture(texType, 
-			width, height, depth, num_mips, format, usage, hwGammaCorrection, multisampleCount);
-	}
-
-	TexturePtr Texture::_createPtr(TextureType texType, UINT32 width, UINT32 height, 
-		int num_mips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
-	{
-		return TextureManager::instance().createTexture(texType, 
-			width, height, num_mips, format, usage, hwGammaCorrection, multisampleCount);
-	}
+#include "BsPixelBuffer.h"
+#include "BsTexture.h"
+#include "BsTextureRTTI.h"
+#include "BsDataStream.h"
+#include "BsException.h"
+#include "BsDebug.h"
+#include "BsCoreThread.h"
+#include "BsAsyncOp.h"
+#include "BsResources.h"
+#include "BsPixelUtil.h"
+
+namespace BansheeEngine 
+{
+	TextureProperties::TextureProperties()
+		:mHeight(32), mWidth(32), mDepth(1), mNumMipmaps(0),
+		mHwGamma(false), mMultisampleCount(0), mTextureType(TEX_TYPE_2D),
+		mFormat(PF_UNKNOWN), mUsage(TU_DEFAULT)
+	{
+
+	}
+
+	TextureProperties::TextureProperties(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
+		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount)
+		:mHeight(height), mWidth(width), mDepth(depth), mNumMipmaps(numMipmaps),
+		mHwGamma(hwGamma), mMultisampleCount(multisampleCount), mTextureType(textureType),
+		mFormat(format), mUsage(usage)
+	{
+
+	}
+
+	bool TextureProperties::hasAlpha() const
+	{
+		return PixelUtil::hasAlpha(mFormat);
+	}
+
+	UINT32 TextureProperties::getNumFaces() const
+	{
+		return getTextureType() == TEX_TYPE_CUBE_MAP ? 6 : 1;
+	}
+
+	void TextureProperties::mapFromSubresourceIdx(UINT32 subresourceIdx, UINT32& face, UINT32& mip) const
+	{
+		UINT32 numMipmaps = getNumMipmaps() + 1;
+
+		face = Math::floorToInt((subresourceIdx) / (float)numMipmaps);
+		mip = subresourceIdx % numMipmaps;
+	}
+
+	UINT32 TextureProperties::mapToSubresourceIdx(UINT32 face, UINT32 mip) const
+	{
+		return face * (getNumMipmaps() + 1) + mip;
+	}
+
+	PixelDataPtr TextureProperties::allocateSubresourceBuffer(UINT32 subresourceIdx) const
+	{
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mapFromSubresourceIdx(subresourceIdx, face, mip);
+
+		UINT32 numMips = getNumMipmaps();
+		UINT32 width = getWidth();
+		UINT32 height = getHeight();
+		UINT32 depth = getDepth();
+
+		UINT32 totalSize = PixelUtil::getMemorySize(width, height, depth, getFormat());
+
+		for (UINT32 j = 0; j < mip; j++)
+		{
+			totalSize = PixelUtil::getMemorySize(width, height, depth, getFormat());
+
+			if (width != 1) width /= 2;
+			if (height != 1) height /= 2;
+			if (depth != 1) depth /= 2;
+		}
+
+		PixelDataPtr dst = bs_shared_ptr_new<PixelData>(width, height, depth, getFormat());
+
+		dst->allocateInternalBuffer();
+
+		return dst;
+	}
+
+	TextureCore::TextureCore(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
+		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initData)
+		:mProperties(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount), 
+		mInitData(initData)
+	{ }
+
+	void TextureCore::initialize()
+	{
+		if (mInitData != nullptr)
+		{
+			writeSubresource(0, *mInitData, true);
+			mInitData->_unlock();
+			mInitData = nullptr;
+		}
+	}
+
+	void TextureCore::writeSubresource(UINT32 subresourceIdx, const PixelData& pixelData, bool discardEntireBuffer)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if(discardEntireBuffer)
+		{
+			if(mProperties.getUsage() != TU_DYNAMIC)
+			{
+				// Buffer discard is enabled but buffer was not created as dynamic. Disabling discard.
+				discardEntireBuffer = false;
+			}
+		}
+		else
+		{
+			if (mProperties.getUsage() == TU_DYNAMIC)
+			{
+				LOGWRN("Buffer discard is not enabled but buffer was not created as dynamic. Enabling discard.");
+				discardEntireBuffer = true;
+			}
+		}
+
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mip);
+
+		writeData(pixelData, mip, face, discardEntireBuffer);
+	}
+
+	void TextureCore::readSubresource(UINT32 subresourceIdx, PixelData& data)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		UINT32 face = 0;
+		UINT32 mip = 0;
+		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mip);
+
+		PixelData& pixelData = static_cast<PixelData&>(data);
+
+		UINT32 mipWidth, mipHeight, mipDepth;
+		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
+			mip, mipWidth, mipHeight, mipDepth);
+
+		if (pixelData.getWidth() != mipWidth || pixelData.getHeight() != mipHeight ||
+			pixelData.getDepth() != mipDepth || pixelData.getFormat() != mProperties.getFormat())
+		{
+			BS_EXCEPT(RenderingAPIException, "Provided buffer is not of valid dimensions or format in order to read from this texture.");
+		}
+
+		readData(pixelData, mip, face);
+	}
+
+	PixelData TextureCore::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mipLevel < 0 || mipLevel > mProperties.getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Invalid mip level: " + toString(mipLevel) + ". Min is 0, max is " + toString(mProperties.getNumMipmaps()));
+
+		if (face < 0 || face >= mProperties.getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(mProperties.getNumFaces()));
+
+		return lockImpl(options, mipLevel, face);
+	}
+
+	void TextureCore::unlock()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		unlockImpl();
+	}
+
+	void TextureCore::copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (target->mProperties.getTextureType() != mProperties.getTextureType())
+			BS_EXCEPT(InvalidParametersException, "Source and destination textures must be of same type and must have the same usage and type.");
+
+		if (mProperties.getFormat() != target->mProperties.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 (target->mProperties.getMultisampleCount() > 0 && mProperties.getMultisampleCount() != target->mProperties.getMultisampleCount())
+			BS_EXCEPT(InvalidParametersException, "When copying to a multisampled texture, source texture must have the same number of samples.");
+
+		UINT32 srcFace = 0;
+		UINT32 srcMipLevel = 0;
+
+		UINT32 destFace = 0;
+		UINT32 destMipLevel = 0;
+
+		mProperties.mapFromSubresourceIdx(srcSubresourceIdx, srcFace, srcMipLevel);
+		target->mProperties.mapFromSubresourceIdx(destSubresourceIdx, destFace, destMipLevel);
+
+		if (destFace >= mProperties.getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
+
+		if (srcFace >= target->mProperties.getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Invalid destination face index");
+
+		if (srcMipLevel > mProperties.getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Source mip level out of range. Valid range is [0, " + toString(mProperties.getNumMipmaps()) + "]");
+
+		if (destMipLevel > target->mProperties.getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Destination mip level out of range. Valid range is [0, " + toString(target->mProperties.getNumMipmaps()) + "]");
+
+		UINT32 srcMipWidth = mProperties.getWidth() >> srcMipLevel;
+		UINT32 srcMipHeight = mProperties.getHeight() >> srcMipLevel;
+		UINT32 srcMipDepth = mProperties.getDepth() >> srcMipLevel;
+
+		UINT32 dstMipWidth = target->mProperties.getWidth() >> destMipLevel;
+		UINT32 dstMipHeight = target->mProperties.getHeight() >> destMipLevel;
+		UINT32 dstMipDepth = target->mProperties.getDepth() >> destMipLevel;
+
+		if (srcMipWidth != dstMipWidth || srcMipHeight != dstMipHeight || srcMipDepth != dstMipDepth)
+			BS_EXCEPT(InvalidParametersException, "Source and destination sizes must match");
+
+		copyImpl(srcFace, srcMipLevel, destFace, destMipLevel, target);
+	}
+
+	/************************************************************************/
+	/* 								TEXTURE VIEW                      		*/
+	/************************************************************************/
+
+	TextureViewPtr TextureCore::createView(const SPtr<TextureCore>& texture, const TEXTURE_VIEW_DESC& desc)
+	{
+		return bs_shared_ptr<TextureView>(new (bs_alloc<TextureView>()) TextureView(texture, desc));
+	}
+
+	void TextureCore::clearBufferViews()
+	{
+		mTextureViews.clear();
+	}
+
+	TextureViewPtr TextureCore::requestView(const SPtr<TextureCore>& texture, UINT32 mostDetailMip, UINT32 numMips, UINT32 firstArraySlice, UINT32 numArraySlices, GpuViewUsage usage)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		assert(texture != nullptr);
+
+		TEXTURE_VIEW_DESC key;
+		key.mostDetailMip = mostDetailMip;
+		key.numMips = numMips;
+		key.firstArraySlice = firstArraySlice;
+		key.numArraySlices = numArraySlices;
+		key.usage = usage;
+
+		auto iterFind = texture->mTextureViews.find(key);
+		if (iterFind == texture->mTextureViews.end())
+		{
+			TextureViewPtr newView = texture->createView(texture, key);
+			texture->mTextureViews[key] = new (bs_alloc<TextureViewReference>()) TextureViewReference(newView);
+
+			iterFind = texture->mTextureViews.find(key);
+		}
+
+		iterFind->second->refCount++;
+		return iterFind->second->view;
+	}
+
+	void TextureCore::releaseView(const TextureViewPtr& view)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		assert(view != nullptr);
+
+		SPtr<TextureCore> texture = view->getTexture();
+
+		auto iterFind = texture->mTextureViews.find(view->getDesc());
+		if (iterFind == texture->mTextureViews.end())
+		{
+			BS_EXCEPT(InternalErrorException, "Trying to release a texture view that doesn't exist!");
+		}
+
+		iterFind->second->refCount--;
+
+		if (iterFind->second->refCount == 0)
+		{
+			TextureViewReference* toRemove = iterFind->second;
+
+			texture->mTextureViews.erase(iterFind);
+
+			bs_delete(toRemove);
+		}
+	}
+
+	Texture::Texture()
+	{
+
+	}
+
+	Texture::Texture(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
+		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount)
+		:mProperties(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount)
+    {
+        
+    }
+
+	Texture::Texture(const PixelDataPtr& pixelData, int usage, bool hwGamma)
+		: mProperties(pixelData->getDepth() > 1 ? TEX_TYPE_3D : TEX_TYPE_2D, pixelData->getWidth(), pixelData->getHeight(),
+		pixelData->getDepth(), 0, pixelData->getFormat(), usage, hwGamma, 0), mInitData(pixelData)
+	{
+		if (mInitData != nullptr)
+			mInitData->_lock();
+	}
+
+	void Texture::initialize()
+	{
+		mSize = calculateSize();
+
+		// Allocate CPU buffers if needed
+		if ((mProperties.getUsage() & TU_CPUCACHED) != 0)
+		{
+			createCPUBuffers();
+
+			if (mInitData != nullptr)
+				updateCPUBuffers(0, *mInitData);
+		}
+
+		Resource::initialize();
+	}
+
+	SPtr<CoreObjectCore> Texture::createCore() const
+	{
+		const TextureProperties& props = getProperties();
+
+		SPtr<CoreObjectCore> coreObj = TextureCoreManager::instance().createTextureInternal(props.getTextureType(), props.getWidth(), props.getHeight(),
+			props.getDepth(), props.getNumMipmaps(), props.getFormat(), props.getUsage(), props.isHardwareGammaEnabled(), props.getMultisampleCount(), mInitData);
+
+		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
+			mInitData = nullptr;
+
+		return coreObj;
+	}
+
+	AsyncOp Texture::writeSubresource(CoreAccessor& accessor, UINT32 subresourceIdx, const PixelDataPtr& data, bool discardEntireBuffer)
+	{
+		updateCPUBuffers(subresourceIdx, *data);
+
+		data->_lock();
+
+		std::function<void(const SPtr<TextureCore>&, UINT32, const PixelDataPtr&, bool, AsyncOp&)> func =
+			[&](const SPtr<TextureCore>& texture, UINT32 _subresourceIdx, const PixelDataPtr& _pixData, bool _discardEntireBuffer, AsyncOp& asyncOp)
+		{
+			texture->writeSubresource(_subresourceIdx, *_pixData, _discardEntireBuffer);
+			_pixData->_unlock();
+			asyncOp._completeOperation();
+
+		};
+
+		return accessor.queueReturnCommand(std::bind(func, getCore(), subresourceIdx,
+			data, discardEntireBuffer, std::placeholders::_1));
+	}
+
+	AsyncOp Texture::readSubresource(CoreAccessor& accessor, UINT32 subresourceIdx, const PixelDataPtr& data)
+	{
+		data->_lock();
+
+		std::function<void(const SPtr<TextureCore>&, UINT32, const PixelDataPtr&, AsyncOp&)> func =
+			[&](const SPtr<TextureCore>& texture, UINT32 _subresourceIdx, const PixelDataPtr& _pixData, AsyncOp& asyncOp)
+		{
+			texture->readSubresource(_subresourceIdx, *_pixData);
+			_pixData->_unlock();
+			asyncOp._completeOperation();
+
+		};
+
+		return accessor.queueReturnCommand(std::bind(func, getCore(), subresourceIdx,
+			data, std::placeholders::_1));
+	}
+
+	UINT32 Texture::calculateSize() const
+	{
+		return mProperties.getNumFaces() * PixelUtil::getMemorySize(mProperties.getWidth(),
+			mProperties.getHeight(), mProperties.getDepth(), mProperties.getFormat());
+	}
+
+	void Texture::updateCPUBuffers(UINT32 subresourceIdx, const PixelData& pixelData)
+	{
+		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
+			return;
+
+		if (subresourceIdx >= (UINT32)mCPUSubresourceData.size())
+		{
+			LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. " + toString(mCPUSubresourceData.size()));
+			return;
+		}
+
+		UINT32 mipLevel;
+		UINT32 face;
+		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mipLevel);
+
+		UINT32 mipWidth, mipHeight, mipDepth;
+		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
+			mipLevel, mipWidth, mipHeight, mipDepth);
+
+		if (pixelData.getWidth() != mipWidth || pixelData.getHeight() != mipHeight ||
+			pixelData.getDepth() != mipDepth || pixelData.getFormat() != mProperties.getFormat())
+		{
+			LOGERR("Provided buffer is not of valid dimensions or format in order to update this texture.");
+			return;
+		}
+
+		if (mCPUSubresourceData[subresourceIdx]->getSize() != pixelData.getSize())
+			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+
+		UINT8* dest = mCPUSubresourceData[subresourceIdx]->getData();
+		UINT8* src = pixelData.getData();
+
+		memcpy(dest, src, pixelData.getSize());
+	}
+
+	void Texture::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	{
+		if ((mProperties.getUsage() & TU_CPUCACHED) == 0)
+		{
+			LOGERR("Attempting to read CPU data from a texture that is created without CPU caching.");
+			return;
+		}
+
+		UINT32 mipWidth, mipHeight, mipDepth;
+		PixelUtil::getSizeForMipLevel(mProperties.getWidth(), mProperties.getHeight(), mProperties.getDepth(),
+			mipLevel, mipWidth, mipHeight, mipDepth);
+
+		if (dest.getWidth() != mipWidth || dest.getHeight() != mipHeight ||
+			dest.getDepth() != mipDepth || dest.getFormat() != mProperties.getFormat())
+		{
+			LOGERR("Provided buffer is not of valid dimensions or format in order to read from this texture.");
+			return;
+		}
+
+		UINT32 subresourceIdx = mProperties.mapToSubresourceIdx(face, mipLevel);
+		if (subresourceIdx >= (UINT32)mCPUSubresourceData.size())
+		{
+			LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. " + toString(mCPUSubresourceData.size()));
+			return;
+		}
+
+		if (mCPUSubresourceData[subresourceIdx]->getSize() != dest.getSize())
+			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+
+		UINT8* srcPtr = mCPUSubresourceData[subresourceIdx]->getData();
+		UINT8* destPtr = dest.getData();
+
+		memcpy(destPtr, srcPtr, dest.getSize());
+	}
+
+	void Texture::createCPUBuffers()
+	{
+		UINT32 numFaces = mProperties.getNumFaces();
+		UINT32 numMips = mProperties.getNumMipmaps() + 1;
+
+		UINT32 numSubresources = numFaces * numMips;
+		mCPUSubresourceData.resize(numSubresources);
+
+		for (UINT32 i = 0; i < numFaces; i++)
+		{
+			UINT32 curWidth = mProperties.getWidth();
+			UINT32 curHeight = mProperties.getHeight();
+			UINT32 curDepth = mProperties.getDepth();
+
+			for (UINT32 j = 0; j < numMips; j++)
+			{
+				UINT32 subresourceIdx = mProperties.mapToSubresourceIdx(i, j);
+
+				mCPUSubresourceData[subresourceIdx] = bs_shared_ptr_new<PixelData>(curWidth, curHeight, curDepth, mProperties.getFormat());
+				mCPUSubresourceData[subresourceIdx]->allocateInternalBuffer();
+
+				if (curWidth > 1)
+					curWidth = curWidth / 2;
+
+				if (curHeight > 1)
+					curHeight = curHeight / 2;
+
+				if (curDepth > 1)
+					curDepth = curDepth / 2;
+			}
+		}
+	}
+
+	SPtr<TextureCore> Texture::getCore() const
+	{
+		return std::static_pointer_cast<TextureCore>(mCoreSpecific);
+	}
+
+	/************************************************************************/
+	/* 								SERIALIZATION                      		*/
+	/************************************************************************/
+
+	RTTITypeBase* Texture::getRTTIStatic()
+	{
+		return TextureRTTI::instance();
+	}
+
+	RTTITypeBase* Texture::getRTTI() const
+	{
+		return Texture::getRTTIStatic();
+	}
+
+	/************************************************************************/
+	/* 								STATICS	                      			*/
+	/************************************************************************/
+	HTexture Texture::create(TextureType texType, UINT32 width, UINT32 height, UINT32 depth, 
+		int numMips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
+	{
+		TexturePtr texturePtr = _createPtr(texType, 
+			width, height, depth, numMips, format, usage, hwGammaCorrection, multisampleCount);
+
+		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
+	}
+	
+	HTexture Texture::create(TextureType texType, UINT32 width, UINT32 height, 
+		int numMips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
+	{
+		TexturePtr texturePtr = _createPtr(texType, 
+			width, height, numMips, format, usage, hwGammaCorrection, multisampleCount);
+
+		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
+	}
+
+	HTexture Texture::create(const PixelDataPtr& pixelData, int usage, bool hwGammaCorrection)
+	{
+		TexturePtr texturePtr = _createPtr(pixelData, usage, hwGammaCorrection);
+
+		return static_resource_cast<Texture>(gResources()._createResourceHandle(texturePtr));
+	}
+
+	TexturePtr Texture::_createPtr(TextureType texType, UINT32 width, UINT32 height, UINT32 depth, 
+		int num_mips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
+	{
+		return TextureManager::instance().createTexture(texType, 
+			width, height, depth, num_mips, format, usage, hwGammaCorrection, multisampleCount);
+	}
+
+	TexturePtr Texture::_createPtr(TextureType texType, UINT32 width, UINT32 height, 
+		int num_mips, PixelFormat format, int usage, bool hwGammaCorrection, UINT32 multisampleCount)
+	{
+		return TextureManager::instance().createTexture(texType, 
+			width, height, num_mips, format, usage, hwGammaCorrection, multisampleCount);
+	}
+
+	TexturePtr Texture::_createPtr(const PixelDataPtr& pixelData, int usage, bool hwGammaCorrection)
+	{
+		return TextureManager::instance().createTexture(pixelData, usage, hwGammaCorrection);
+	}
 }
 }

+ 8 - 3
BansheeEngine/Include/BsBuiltinResources.h

@@ -127,6 +127,9 @@ namespace BansheeEngine
 		/**	Generates the builtin meshes. */
 		/**	Generates the builtin meshes. */
 		void generateMeshes();
 		void generateMeshes();
 
 
+		/**	Generates the builtin textures. */
+		void generateTextures();
+
 		/**	Loads a GUI skin texture with the specified filename. */
 		/**	Loads a GUI skin texture with the specified filename. */
 		HSpriteTexture getSkinTexture(const WString& name);
 		HSpriteTexture getSkinTexture(const WString& name);
 
 
@@ -174,6 +177,7 @@ namespace BansheeEngine
 		Path mEngineShaderFolder;
 		Path mEngineShaderFolder;
 		Path mEngineShaderIncludeFolder;
 		Path mEngineShaderIncludeFolder;
 		Path mEngineMeshFolder;
 		Path mEngineMeshFolder;
+		Path mEngineTextureFolder;
 
 
 		Path ResourceManifestPath;
 		Path ResourceManifestPath;
 
 
@@ -183,6 +187,7 @@ namespace BansheeEngine
 		static const char* ShaderIncludeFolder;
 		static const char* ShaderIncludeFolder;
 		static const char* SkinFolder;
 		static const char* SkinFolder;
 		static const char* MeshFolder;
 		static const char* MeshFolder;
+		static const char* TextureFolder;
 
 
 		static const WString DefaultFontFilename;
 		static const WString DefaultFontFilename;
 		static const UINT32 DefaultFontSize;
 		static const UINT32 DefaultFontSize;
@@ -289,9 +294,9 @@ namespace BansheeEngine
 		static const WString MeshQuadFile;
 		static const WString MeshQuadFile;
 		static const WString MeshDiscFile;
 		static const WString MeshDiscFile;
 
 
-		static HTexture sWhiteTexture;
-		static HTexture sBlackTexture;
-		static HTexture sNormalTexture;
+		static const WString TextureWhiteFile;
+		static const WString TextureBlackFile;
+		static const WString TextureNormalFile;
 	};
 	};
 
 
 	/**	Provides various methods commonly used for managing builtin resources. */
 	/**	Provides various methods commonly used for managing builtin resources. */

+ 81 - 46
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -45,10 +45,7 @@ namespace BansheeEngine
 	const char* BuiltinResources::SkinFolder = "Skin\\";
 	const char* BuiltinResources::SkinFolder = "Skin\\";
 	const char* BuiltinResources::ShaderIncludeFolder = "Includes\\";
 	const char* BuiltinResources::ShaderIncludeFolder = "Includes\\";
 	const char* BuiltinResources::MeshFolder = "Meshes\\";
 	const char* BuiltinResources::MeshFolder = "Meshes\\";
-
-	HTexture BuiltinResources::sWhiteTexture;
-	HTexture BuiltinResources::sBlackTexture;
-	HTexture BuiltinResources::sNormalTexture;
+	const char* BuiltinResources::TextureFolder = "Textures\\";
 
 
 	/************************************************************************/
 	/************************************************************************/
 	/* 								GUI TEXTURES                      		*/
 	/* 								GUI TEXTURES                      		*/
@@ -170,6 +167,14 @@ namespace BansheeEngine
 	const WString BuiltinResources::MeshQuadFile = L"Quad.asset";
 	const WString BuiltinResources::MeshQuadFile = L"Quad.asset";
 	const WString BuiltinResources::MeshDiscFile = L"Disc.asset";
 	const WString BuiltinResources::MeshDiscFile = L"Disc.asset";
 
 
+	/************************************************************************/
+	/* 								TEXTURES							  	*/
+	/************************************************************************/
+
+	const WString BuiltinResources::TextureWhiteFile = L"White.asset";
+	const WString BuiltinResources::TextureBlackFile = L"Black.asset";
+	const WString BuiltinResources::TextureNormalFile = L"Normal.asset";
+
 	BuiltinResources::~BuiltinResources()
 	BuiltinResources::~BuiltinResources()
 	{
 	{
 		mCursorArrow = nullptr;
 		mCursorArrow = nullptr;
@@ -202,6 +207,7 @@ namespace BansheeEngine
 		mEngineShaderFolder = mBuiltinDataFolder + ShaderFolder;
 		mEngineShaderFolder = mBuiltinDataFolder + ShaderFolder;
 		mEngineShaderIncludeFolder = mBuiltinDataFolder + ShaderIncludeFolder;
 		mEngineShaderIncludeFolder = mBuiltinDataFolder + ShaderIncludeFolder;
 		mEngineMeshFolder = mBuiltinDataFolder + MeshFolder;
 		mEngineMeshFolder = mBuiltinDataFolder + MeshFolder;
+		mEngineTextureFolder = mBuiltinDataFolder + TextureFolder;
 
 
 		ResourceManifestPath = mBuiltinDataFolder + "ResourceManifest.asset";
 		ResourceManifestPath = mBuiltinDataFolder + "ResourceManifest.asset";
 
 
@@ -318,6 +324,9 @@ namespace BansheeEngine
 
 
 	void BuiltinResources::preprocess()
 	void BuiltinResources::preprocess()
 	{
 	{
+		// Hidden dependency: Textures need to be generated before shaders as they may use the default textures
+		generateTextures();
+
 		BuiltinResourcesHelper::importAssets(mEngineRawCursorFolder, mEngineCursorFolder, mResourceManifest);
 		BuiltinResourcesHelper::importAssets(mEngineRawCursorFolder, mEngineCursorFolder, mResourceManifest);
 		BuiltinResourcesHelper::importAssets(mEngineRawIconFolder, mEngineIconFolder, mResourceManifest);
 		BuiltinResourcesHelper::importAssets(mEngineRawIconFolder, mEngineIconFolder, mResourceManifest);
 		BuiltinResourcesHelper::importAssets(mEngineRawShaderIncludeFolder, mEngineShaderIncludeFolder, mResourceManifest); // Hidden dependency: Includes must be imported before shaders
 		BuiltinResourcesHelper::importAssets(mEngineRawShaderIncludeFolder, mEngineShaderIncludeFolder, mResourceManifest); // Hidden dependency: Includes must be imported before shaders
@@ -801,6 +810,62 @@ namespace BansheeEngine
 		return skin;
 		return skin;
 	}
 	}
 
 
+	void BuiltinResources::generateTextures()
+	{
+		PixelDataPtr blackPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+		blackPixelData->setColorAt(Color::Black, 0, 0);
+		blackPixelData->setColorAt(Color::Black, 0, 1);
+		blackPixelData->setColorAt(Color::Black, 1, 0);
+		blackPixelData->setColorAt(Color::Black, 1, 1);
+
+		TexturePtr blackTexture = Texture::_createPtr(blackPixelData);
+
+		PixelDataPtr whitePixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+		whitePixelData->setColorAt(Color::White, 0, 0);
+		whitePixelData->setColorAt(Color::White, 0, 1);
+		whitePixelData->setColorAt(Color::White, 1, 0);
+		whitePixelData->setColorAt(Color::White, 1, 1);
+
+		TexturePtr whiteTexture = Texture::_createPtr(whitePixelData);
+
+		PixelDataPtr normalPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+
+		Color encodedNormal(0.5f, 0.5f, 1.0f);
+		normalPixelData->setColorAt(encodedNormal, 0, 0);
+		normalPixelData->setColorAt(encodedNormal, 0, 1);
+		normalPixelData->setColorAt(encodedNormal, 1, 0);
+		normalPixelData->setColorAt(encodedNormal, 1, 1);
+
+		TexturePtr normalTexture = Texture::_createPtr(normalPixelData);
+
+		// Save all textures
+		Path outputDir = FileSystem::getWorkingDirectoryPath() + mEngineTextureFolder;
+
+		auto saveTexture = [&](const Path& path, const SPtr<Texture>& texture)
+		{
+			HResource textureResource;
+			if (FileSystem::exists(path))
+				textureResource = gResources().load(path);
+
+			if (textureResource.isLoaded())
+				gResources().update(textureResource, texture);
+			else
+				textureResource = gResources()._createResourceHandle(texture);
+
+			gResources().save(textureResource, path, true);
+			mResourceManifest->registerResource(textureResource.getUUID(), path);
+		};
+
+		Path whitePath = outputDir + TextureWhiteFile;
+		saveTexture(whitePath, whiteTexture);
+
+		Path blackPath = outputDir + TextureBlackFile;
+		saveTexture(blackPath, blackTexture);
+
+		Path normalPath = outputDir + TextureNormalFile;
+		saveTexture(normalPath, normalTexture);
+	}
+
 	void BuiltinResources::generateMeshes()
 	void BuiltinResources::generateMeshes()
 	{
 	{
 		VertexDataDescPtr vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
 		VertexDataDescPtr vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
@@ -1025,54 +1090,24 @@ namespace BansheeEngine
 
 
 	HTexture BuiltinResources::getTexture(BuiltinTexture type)
 	HTexture BuiltinResources::getTexture(BuiltinTexture type)
 	{
 	{
-		switch(type)
+		Path texturePath = FileSystem::getWorkingDirectoryPath();
+		texturePath.append(Paths::getEngineDataPath());
+		texturePath.append(TextureFolder);
+
+		switch (type)
 		{
 		{
 		case BuiltinTexture::Black:
 		case BuiltinTexture::Black:
-			if(sBlackTexture == nullptr)
-			{
-				PixelDataPtr blackPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
-
-				blackPixelData->setColorAt(Color::Black, 0, 0);
-				blackPixelData->setColorAt(Color::Black, 0, 1);
-				blackPixelData->setColorAt(Color::Black, 1, 0);
-				blackPixelData->setColorAt(Color::Black, 1, 1);
-
-				sBlackTexture = Texture::create(blackPixelData);
-			}
-
-			return sBlackTexture;
+			texturePath.append(TextureBlackFile);
+			break;
 		case BuiltinTexture::White:
 		case BuiltinTexture::White:
-			if (sWhiteTexture == nullptr)
-			{
-				PixelDataPtr whitePixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
-
-				whitePixelData->setColorAt(Color::White, 0, 0);
-				whitePixelData->setColorAt(Color::White, 0, 1);
-				whitePixelData->setColorAt(Color::White, 1, 0);
-				whitePixelData->setColorAt(Color::White, 1, 1);
-
-				sWhiteTexture = Texture::create(whitePixelData);
-			}
-
-			return sWhiteTexture;
+			texturePath.append(TextureWhiteFile);
+			break;
 		case BuiltinTexture::Normal:
 		case BuiltinTexture::Normal:
-			if (sNormalTexture == nullptr)
-			{
-				PixelDataPtr normalPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
-
-				Color encodedNormal(0.0f, 0.0f, 1.0f);
-				normalPixelData->setColorAt(encodedNormal, 0, 0);
-				normalPixelData->setColorAt(encodedNormal, 0, 1);
-				normalPixelData->setColorAt(encodedNormal, 1, 0);
-				normalPixelData->setColorAt(encodedNormal, 1, 1);
-
-				sNormalTexture = Texture::create(normalPixelData);
-			}
-
-			return sNormalTexture;
+			texturePath.append(TextureNormalFile);
+			break;
 		}
 		}
 
 
-		return HTexture();
+		return gResources().load<Texture>(texturePath);
 	}
 	}
 
 
 	HMaterial BuiltinResources::createSpriteTextMaterial() const
 	HMaterial BuiltinResources::createSpriteTextMaterial() const

+ 3 - 3
BansheeSL/Source/BsSLFXCompiler.cpp

@@ -1716,11 +1716,11 @@ namespace BansheeEngine
 
 
 	HTexture BSLFXCompiler::getBuiltinTexture(const String& name)
 	HTexture BSLFXCompiler::getBuiltinTexture(const String& name)
 	{
 	{
-		if (StringUtil::compare(name, String("white"), false))
+		if (StringUtil::compare(name, String("white"), false) == 0)
 			return BuiltinResources::getTexture(BuiltinTexture::White);
 			return BuiltinResources::getTexture(BuiltinTexture::White);
-		else if (StringUtil::compare(name, String("black"), false))
+		else if (StringUtil::compare(name, String("black"), false) == 0)
 			return BuiltinResources::getTexture(BuiltinTexture::Black);
 			return BuiltinResources::getTexture(BuiltinTexture::Black);
-		else if (StringUtil::compare(name, String("normal"), false))
+		else if (StringUtil::compare(name, String("normal"), false) == 0)
 			return BuiltinResources::getTexture(BuiltinTexture::Normal);
 			return BuiltinResources::getTexture(BuiltinTexture::Normal);
 
 
 		return HTexture();
 		return HTexture();

+ 1 - 1
Scripts/VSVisualizations.natvis

@@ -9,7 +9,7 @@
 	</Expand>
 	</Expand>
   </Type>
   </Type>
   
   
-  <Type Name="BansheeEngine::ResourceHandle&lt;*&gt;">
+  <Type Name="BansheeEngine::ResourceHandleBase&lt;*&gt;">
 	<DisplayString Condition="mData._Ptr == 0 || mData._Ptr->mPtr._Ptr == 0">Empty</DisplayString>
 	<DisplayString Condition="mData._Ptr == 0 || mData._Ptr->mPtr._Ptr == 0">Empty</DisplayString>
     <DisplayString>Name = {mData._Ptr->mPtr._Ptr->mMetaData._Ptr->displayName}, UUID = {mData._Ptr->mUUID}</DisplayString>
     <DisplayString>Name = {mData._Ptr->mPtr._Ptr->mMetaData._Ptr->displayName}, UUID = {mData._Ptr->mUUID}</DisplayString>
 	<Expand>	
 	<Expand>