Jelajahi Sumber

Fixed a crash when reading non-top mip level from a texture
Fixed a crash when maximizing docked widgets
Fixed an issue that made it impossible to assign materials in renderable inspector
Fixed an issue with loading a renderable that has multiple materials saved
Fixed a crash on shutdown due to unreleased core resources on a non-core object

BearishSun 10 tahun lalu
induk
melakukan
92f409a13d

+ 9 - 5
BansheeCore/Source/BsResources.cpp

@@ -329,11 +329,15 @@ namespace BansheeEngine
 		fs.skip(); // Skipped over saved resource data
 		std::shared_ptr<IReflectable> loadedData = fs.decode();
 
-		if(loadedData == nullptr)
-			BS_EXCEPT(InternalErrorException, "Unable to load resource.");
-
-		if(!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
-			BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
+		if (loadedData == nullptr)
+		{
+			LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
+		}
+		else
+		{
+			if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
+				BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
+		}
 
 		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
 		return resource;

+ 22 - 22
BansheeCore/Source/BsTextureImportOptions.cpp

@@ -1,23 +1,23 @@
-#include "BsTextureImportOptions.h"
-#include "BsTextureImportOptionsRTTI.h"
-
-namespace BansheeEngine
-{
-	TextureImportOptions::TextureImportOptions()
-		:mFormat(PF_R8G8B8A8), mGenerateMips(false), mMaxMip(0), 
-		mCPUReadable(false), mSRGB(false)
-	{ }
-
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
-	RTTITypeBase* TextureImportOptions::getRTTIStatic()
-	{
-		return TextureImportOptionsRTTI::instance();
-	}
-
-	RTTITypeBase* TextureImportOptions::getRTTI() const
-	{
-		return TextureImportOptions::getRTTIStatic();
-	}
+#include "BsTextureImportOptions.h"
+#include "BsTextureImportOptionsRTTI.h"
+
+namespace BansheeEngine
+{
+	TextureImportOptions::TextureImportOptions()
+		:mFormat(PF_R8G8B8A8), mGenerateMips(true), mMaxMip(0), 
+		mCPUReadable(false), mSRGB(false)
+	{ }
+
+	/************************************************************************/
+	/* 								SERIALIZATION                      		*/
+	/************************************************************************/
+	RTTITypeBase* TextureImportOptions::getRTTIStatic()
+	{
+		return TextureImportOptionsRTTI::instance();
+	}
+
+	RTTITypeBase* TextureImportOptions::getRTTI() const
+	{
+		return TextureImportOptions::getRTTIStatic();
+	}
 }

+ 3 - 3
BansheeD3D11RenderAPI/Source/BsD3D11Texture.cpp

@@ -101,9 +101,9 @@ namespace BansheeEngine
 		}
 #endif
 
-		UINT32 mipWidth = mProperties.getWidth() >> mipLevel;
-		UINT32 mipHeight = mProperties.getHeight() >> mipLevel;
-		UINT32 mipDepth = mProperties.getDepth() >> mipLevel;
+		UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
+		UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
+		UINT32 mipDepth = std::max(1u, mProperties.getDepth() >> mipLevel);
 
 		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
 

+ 1142 - 1142
BansheeD3D9RenderAPI/Source/BsD3D9Texture.cpp

@@ -1,1143 +1,1143 @@
-#include "BsCoreThread.h"
-#include "BsD3D9Texture.h"
-#include "BsD3D9PixelBuffer.h"
-#include "BsException.h"
-#include "BsBitwise.h"
-#include "BsD3D9Mappings.h"
-#include "BsD3D9RenderAPI.h"
-#include "BsD3D9TextureManager.h"
-#include "BsD3D9Device.h"
-#include "BsD3D9DeviceManager.h"
-#include "BsD3D9ResourceManager.h"
-#include "BsRenderStats.h"
-#include "BsPixelData.h"
-
-namespace BansheeEngine 
-{
-	D3D9TextureCore::D3D9TextureCore(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
-		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initialData)
-		:TextureCore(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount, initialData),
-		mD3DPool(D3DPOOL_MANAGED), mDynamicTextures(false), mHwGammaReadSupported(false), mHwGammaWriteSupported(false), 
-		mMultisampleType(D3DMULTISAMPLE_NONE), mMultisampleQuality(0), mIsBindableAsShaderResource(true)
-	{
-
-	}
-	
-	D3D9TextureCore::~D3D9TextureCore()
-	{	
-		THROW_IF_NOT_CORE_THREAD;
-
-		for (auto& resPair : mMapDeviceToTextureResources)
-		{
-			TextureResources* textureResource = resPair.second;
-
-			freeTextureResources(resPair.first, textureResource);
-		}
-
-		for (auto& resPair : mMapDeviceToTextureResources)
-		{
-			TextureResources* textureResource = resPair.second;
-
-			if (textureResource != nullptr)
-				bs_delete(textureResource);
-		}
-
-		mMapDeviceToTextureResources.clear();
-		mSurfaceList.clear();
-
-		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
-	}
-
-	void D3D9TextureCore::initialize()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		for (UINT32 i = 0; i < D3D9RenderAPI::getResourceCreationDeviceCount(); ++i)
-		{
-			IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getResourceCreationDevice(i);
-
-			createInternalResources(d3d9Device);
-		}
-
-		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
-		TextureCore::initialize();
-	}
-
-	PixelData D3D9TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		if(mLockedBuffer != nullptr)
-			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
-
-		if (mProperties.getUsage() == TU_DEPTHSTENCIL)
-			BS_EXCEPT(InternalErrorException, "Cannot lock a depth stencil texture.");
-
-		UINT32 mipWidth = mProperties.getWidth() >> mipLevel;
-		UINT32 mipHeight = mProperties.getHeight() >> mipLevel;
-		UINT32 mipDepth = mProperties.getDepth() >> mipLevel;
-
-		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
-
-		mLockedBuffer = getBuffer(face, mipLevel);
-		lockedArea.setExternalBuffer((UINT8*)mLockedBuffer->lock(options));
-
-		return lockedArea;
-	}
-	
-	void D3D9TextureCore::unlockImpl()
-	{
-		if(mLockedBuffer == nullptr)
-			BS_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
-
-		mLockedBuffer->unlock();
-		mLockedBuffer = nullptr;
-	}
-
-	void D3D9TextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		if (mProperties.getUsage() == TU_DEPTHSTENCIL || mProperties.getUsage() == TU_RENDERTARGET) // Render targets cannot be locked normally
-		{
-			IDirect3DDevice9* device = D3D9RenderAPI::getActiveD3D9Device();
-
-			D3D9PixelBuffer* sourceBuffer = static_cast<D3D9PixelBuffer*>(getBuffer(face, mipLevel).get());
-			
-			UINT32 mipWidth = mProperties.getWidth() >> mipLevel;
-			UINT32 mipHeight = mProperties.getHeight() >> mipLevel;
-			D3DFORMAT format = chooseD3DFormat(device);
-
-			// Note: I'm allocating and releasing a texture every time we read.
-			// I might consider adding a flag to keep this texture permanent which would make reading
-			// faster but at the cost of double the memory.
-
-			IDirect3DTexture9* stagingTexture = nullptr; 
-			HRESULT hr = D3DXCreateTexture(device, (UINT)mipWidth, (UINT)mipHeight, 1,
-				0, format, D3DPOOL_SYSTEMMEM, &stagingTexture);
-
-			if (FAILED(hr))
-			{
-				String msg = DXGetErrorDescription(hr);
-				BS_EXCEPT(RenderingAPIException, "Failed to create a texture: " + msg);
-			}
-
-			IDirect3DSurface9* stagingSurface = nullptr;
-			hr = stagingTexture->GetSurfaceLevel(0, &stagingSurface);
-			if (FAILED(hr))
-			{
-				String msg = DXGetErrorDescription(hr);
-				BS_EXCEPT(RenderingAPIException, "Failed to retrieve a texture surface: " + msg);
-			}
-
-			hr = device->GetRenderTargetData(sourceBuffer->getSurface(device), stagingSurface);
-			if (FAILED(hr))
-			{
-				String msg = DXGetErrorDescription(hr);
-				BS_EXCEPT(RenderingAPIException, "Failed to retrieve render target data: " + msg);
-			}
-
-			PixelData myData(mipWidth, mipHeight, 1, mProperties.getFormat());
-
-			D3DLOCKED_RECT lrect;
-			hr = stagingSurface->LockRect(&lrect, nullptr, D3DLOCK_READONLY);
-			if (FAILED(hr))
-			{
-				String msg = DXGetErrorDescription(hr);
-				BS_EXCEPT(RenderingAPIException, "Failed to lock surface: " + msg);
-			}
-
-			D3D9PixelBuffer::initPixelDataFromD3DLock(myData, lrect);
-
-#if BS_DEBUG_MODE
-			if (dest.getConsecutiveSize() != myData.getConsecutiveSize())
-				BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
-#endif
-
-			PixelUtil::bulkPixelConversion(myData, dest);
-
-			hr = stagingSurface->UnlockRect();
-			if (FAILED(hr))
-			{
-				String msg = DXGetErrorDescription(hr);
-				BS_EXCEPT(RenderingAPIException, "Failed to unlock surface: " + msg);
-			}
-
-			SAFE_RELEASE(stagingSurface);
-			SAFE_RELEASE(stagingTexture);
-		}
-		else
-		{
-			PixelData myData = lock(GBL_READ_ONLY, mipLevel, face);
-
-#if BS_DEBUG_MODE
-			if (dest.getConsecutiveSize() != myData.getConsecutiveSize())
-			{
-				unlock();
-				BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
-			}
-#endif
-
-			PixelUtil::bulkPixelConversion(myData, dest);
-
-			unlock();
-		}
-	}
-
-	void D3D9TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		if (mProperties.getUsage() == TU_DYNAMIC || mProperties.getUsage() == TU_STATIC)
-		{
-			PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mipLevel, face);
-			PixelUtil::bulkPixelConversion(src, myData);
-			unlock();
-		}
-		else
-		{
-			BS_EXCEPT(RenderingAPIException, "Trying to write into a buffer with unsupported usage: " + toString(mProperties.getUsage()));
-		}
-	}
-	
-	void D3D9TextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		TextureType texType = mProperties.getTextureType();
-
-		if (texType == TEX_TYPE_1D || texType == TEX_TYPE_3D)
-			BS_EXCEPT(NotImplementedException, "Copy not implemented for 1D and 3D textures yet.");
-
-        HRESULT hr;
-		D3D9TextureCore* other = static_cast<D3D9TextureCore*>(target.get());
-
-		for (auto& resPair : mMapDeviceToTextureResources)
-		{
-			TextureResources* srcTextureResource = resPair.second;
-			TextureResources* dstTextureResource = other->getTextureResources(resPair.first);
-
-			IDirect3DSurface9 *sourceSurface = nullptr;
-			IDirect3DSurface9 *destSurface = nullptr;
-
-			if (texType == TEX_TYPE_2D && srcTextureResource->pNormTex != nullptr && dstTextureResource->pNormTex != nullptr)
-			{			
-				if(FAILED(hr = srcTextureResource->pNormTex->GetSurfaceLevel(srcMipLevel, &sourceSurface)))
-				{
-					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
-				}
-
-				if(FAILED(hr = dstTextureResource->pNormTex->GetSurfaceLevel(destMipLevel, &destSurface)))
-				{
-					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
-				}
-			}
-			else if (texType == TEX_TYPE_CUBE_MAP && srcTextureResource->pCubeTex != nullptr && dstTextureResource->pCubeTex != nullptr)
-			{				
-				IDirect3DSurface9 *sourceSurface = nullptr;
-				if (FAILED(hr = srcTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)srcFace, srcMipLevel, &sourceSurface)))
-				{
-					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
-				}
-
-				IDirect3DSurface9 *destSurface = nullptr;
-				if (FAILED(hr = dstTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)destFace, destMipLevel, &destSurface)))
-				{
-					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
-				}
-			}
-
-			if (sourceSurface != nullptr && destSurface != nullptr)
-			{
-				D3DSURFACE_DESC desc;
-
-				sourceSurface->GetDesc(&desc);
-				if (desc.Pool != D3DPOOL_DEFAULT)
-					BS_EXCEPT(InvalidStateException, "Source surface must be in the default pool.");
-
-				destSurface->GetDesc(&desc);
-				if (desc.Pool != D3DPOOL_DEFAULT)
-					BS_EXCEPT(InvalidStateException, "Destination surface must be in the default pool.");
-
-				if (FAILED(hr = resPair.first->StretchRect(sourceSurface, NULL, destSurface, NULL, D3DTEXF_NONE)))
-				{
-					String msg = DXGetErrorDescription(hr);
-					BS_EXCEPT(RenderingAPIException, "StretchRect failed during copy: " + msg);
-				}
-			}
-
-			SAFE_RELEASE(sourceSurface);
-			SAFE_RELEASE(destSurface);
-		}		
-	}
-	
-	D3D9TextureCore::TextureResources* D3D9TextureCore::getTextureResources(IDirect3DDevice9* d3d9Device)
-	{		
-		auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
-
-		if (iterFind == mMapDeviceToTextureResources.end())		
-			return nullptr;		
-		
-		return iterFind->second;
-	}
-
-	D3D9TextureCore::TextureResources* D3D9TextureCore::allocateTextureResources(IDirect3DDevice9* d3d9Device)
-	{
-		assert(mMapDeviceToTextureResources.find(d3d9Device) == mMapDeviceToTextureResources.end());
-
-		TextureResources* textureResources = bs_new<TextureResources>();
-
-		textureResources->pNormTex = nullptr;
-		textureResources->pCubeTex = nullptr;
-		textureResources->pVolumeTex = nullptr;
-		textureResources->pBaseTex = nullptr;
-		textureResources->pMultisampleSurface = nullptr;
-		textureResources->pDepthStencilSurface = nullptr;
-
-		mMapDeviceToTextureResources[d3d9Device] = textureResources;
-
-		return textureResources;
-	}
-	
-	void D3D9TextureCore::freeTextureResources(IDirect3DDevice9* d3d9Device, D3D9TextureCore::TextureResources* textureResources)
-	{		
-		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
-
-		// Release surfaces from each mip level.
-		for(unsigned int i = 0; i < mSurfaceList.size(); ++i)
-		{
-			D3D9PixelBuffer* pixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[i].get());
-
-			pixelBuffer->releaseSurfaces(d3d9Device);			
-		}
-		
-		// Release the rest of the resources.
-		SAFE_RELEASE(textureResources->pBaseTex);
-		SAFE_RELEASE(textureResources->pNormTex);
-		SAFE_RELEASE(textureResources->pCubeTex);
-		SAFE_RELEASE(textureResources->pVolumeTex);
-		SAFE_RELEASE(textureResources->pMultisampleSurface);
-		SAFE_RELEASE(textureResources->pDepthStencilSurface);
-	}
-	
-	UINT32 D3D9TextureCore::calculateSize() const
-	{
-		UINT32 instanceSize = mProperties.getNumFaces() * 
-			PixelUtil::getMemorySize(mProperties.getWidth(), mProperties.getHeight(), 
-			mProperties.getDepth(), mProperties.getFormat());
-
-		return instanceSize * (UINT32)mMapDeviceToTextureResources.size();
-	}
-	
-	void D3D9TextureCore::determinePool()
-	{
-		if (useDefaultPool())
-			mD3DPool = D3DPOOL_DEFAULT;
-		else
-			mD3DPool = D3DPOOL_MANAGED;
-	}
-	
-	void D3D9TextureCore::createInternalResources(IDirect3DDevice9* d3d9Device)
-	{		
-		switch (mProperties.getTextureType())
-		{
-		case TEX_TYPE_1D:
-		case TEX_TYPE_2D:
-			createNormTex(d3d9Device);
-			break;
-		case TEX_TYPE_CUBE_MAP:
-			createCubeTex(d3d9Device);
-			break;
-		case TEX_TYPE_3D:
-			createVolumeTex(d3d9Device);
-			break;
-		default:
-			BS_EXCEPT(InternalErrorException, "Unknown texture type.");
-		}
-	}
-
-	void D3D9TextureCore::createNormTex(IDirect3DDevice9* d3d9Device)
-	{
-		UINT32 width = mProperties.getWidth();
-		UINT32 height = mProperties.getHeight();
-		int texUsage = mProperties.getUsage();
-		UINT32 origNumMips = mProperties.getNumMipmaps();
-		PixelFormat format = mProperties.getFormat();
-		bool hwGamma = mProperties.isHardwareGammaEnabled();
-		UINT32 sampleCount = mProperties.getMultisampleCount();
-
-		assert(width > 0 || height > 0);
-
-		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
-		if (format != D3D9Mappings::_getPF(d3dPF))
-		{
-			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
-		}
-
-		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
-		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
-
-		DWORD usage = 0;
-		if ((texUsage & TU_RENDERTARGET) != 0)
-			usage = D3DUSAGE_RENDERTARGET;
-		else if ((texUsage & TU_DEPTHSTENCIL) != 0)
-			usage = D3DUSAGE_DEPTHSTENCIL;
-
-		// Check dynamic textures
-		if (texUsage & TU_DYNAMIC)
-		{
-			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF))
-			{
-				usage |= D3DUSAGE_DYNAMIC;
-				mDynamicTextures = true;
-			}
-			else
-			{
-				mDynamicTextures = false;
-			}
-		}
-
-		// Check sRGB support
-		if (hwGamma)
-		{
-			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF, false);
-			if (texUsage & TU_RENDERTARGET)
-				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF, true);
-		}
-
-		// Check multisample level
-		if ((texUsage & TU_RENDERTARGET) != 0 || (texUsage & TU_DEPTHSTENCIL) != 0)
-		{
-			D3D9RenderAPI* rsys = static_cast<D3D9RenderAPI*>(BansheeEngine::RenderAPICore::instancePtr());
-			rsys->determineMultisampleSettings(d3d9Device, sampleCount, d3dPF, false, &mMultisampleType, &mMultisampleQuality);
-		}
-		else
-		{
-			mMultisampleType = D3DMULTISAMPLE_NONE;
-			mMultisampleQuality = 0;
-		}
-
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& rkCurCaps = device->getD3D9DeviceCaps();			
-
-		// Check if mip maps are supported on hardware
-		if (numMips > 1 && (!(rkCurCaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) || (texUsage & TU_RENDERTARGET) != 0 || (texUsage & TU_DEPTHSTENCIL) != 0))
-		{
-			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
-		}
-
-		determinePool();
-		TextureResources* textureResources;			
-	
-		// Get or create new texture resources structure.
-		textureResources = getTextureResources(d3d9Device);
-		if (textureResources != NULL)
-			freeTextureResources(d3d9Device, textureResources);
-		else
-			textureResources = allocateTextureResources(d3d9Device);
-
-		if ((texUsage & TU_RENDERTARGET) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
-		{
-			// Create AA surface
-			HRESULT hr = d3d9Device->CreateRenderTarget(width, height, d3dPF, 
-				mMultisampleType, mMultisampleQuality,
-				FALSE,
-				&textureResources->pMultisampleSurface, NULL);
-
-			if (FAILED(hr))
-				BS_EXCEPT(RenderingAPIException, "Unable to create AA render target: " + String(DXGetErrorDescription(hr)));
-
-			D3DSURFACE_DESC desc;
-			hr = textureResources->pMultisampleSurface->GetDesc(&desc);
-			if (FAILED(hr))
-			{
-				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
-			}
-
-			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
-
-			mIsBindableAsShaderResource = false; // Cannot bind AA surfaces
-		}
-		else if ((texUsage & TU_DEPTHSTENCIL) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
-		{
-			// Create AA depth stencil surface
-			HRESULT hr = d3d9Device->CreateDepthStencilSurface(width, height, d3dPF, 
-				mMultisampleType, mMultisampleQuality,
-				FALSE, 
-				&textureResources->pDepthStencilSurface, NULL);
-
-			if (FAILED(hr))
-				BS_EXCEPT(RenderingAPIException, "Unable to create AA depth stencil render target: " + String(DXGetErrorDescription(hr)));
-
-			// Update final parameters as they may differ from requested ones
-			D3DSURFACE_DESC desc;
-			hr = textureResources->pDepthStencilSurface->GetDesc(&desc);
-			if (FAILED(hr))
-			{
-				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
-			}
-
-			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
-
-			mIsBindableAsShaderResource = false; // Cannot bind AA depth buffer
-		}
-		else
-		{
-			// Create normal texture
-			HRESULT hr = D3DXCreateTexture(d3d9Device, (UINT)width, (UINT)height, numMips,
-				usage, d3dPF, mD3DPool, &textureResources->pNormTex);
-
-			if (FAILED(hr))
-			{
-				BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
-			}
-
-			hr = textureResources->pNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&textureResources->pBaseTex);
-			if (FAILED(hr))
-			{
-				BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
-			}
-
-			// Update final parameters as they may differ from requested ones
-			D3DSURFACE_DESC desc;
-			hr = textureResources->pNormTex->GetLevelDesc(0, &desc);
-			if (FAILED(hr))
-			{
-				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
-			}
-
-			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
-		}
-	}
-	
-	void D3D9TextureCore::createCubeTex(IDirect3DDevice9* d3d9Device)
-	{
-		UINT32 width = mProperties.getWidth();
-		UINT32 height = mProperties.getHeight();
-		int texUsage = mProperties.getUsage();
-		UINT32 origNumMips = mProperties.getNumMipmaps();
-		PixelFormat format = mProperties.getFormat();
-		bool hwGamma = mProperties.isHardwareGammaEnabled();
-
-		assert(width > 0 || height > 0);
-
-		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
-		if (format != D3D9Mappings::_getPF(d3dPF))
-		{
-			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
-		}
-
-		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
-		DWORD usage = (texUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
-		usage |= (texUsage & TU_DEPTHSTENCIL) ? D3DUSAGE_DEPTHSTENCIL : 0;
-
-		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
-
-		// Check dynamic textures
-		if (texUsage & TU_DYNAMIC)
-		{
-			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF))
-			{
-				usage |= D3DUSAGE_DYNAMIC;
-				mDynamicTextures = true;
-			}
-			else
-			{
-				mDynamicTextures = false;
-			}
-		}
-
-		// Check sRGB support
-		if (hwGamma)
-		{
-			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF, false);
-			if (texUsage & TU_RENDERTARGET)
-				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF, true);
-		}
-
-		// No multisampling on cube textures
-		mMultisampleType = D3DMULTISAMPLE_NONE;
-		mMultisampleQuality = 0;
-
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();			
-		
-		// Check if mip map cube textures are supported
-		if (numMips > 1 && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP))
-		{
-			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
-		}
-
-		determinePool();
-		TextureResources* textureResources;			
-
-		// Get or create new texture resources structure.
-		textureResources = getTextureResources(d3d9Device);
-		if (textureResources != NULL)
-			freeTextureResources(d3d9Device, textureResources);
-		else
-			textureResources = allocateTextureResources(d3d9Device);
-
-		// Create the texture
-		HRESULT hr = D3DXCreateCubeTexture(d3d9Device, (UINT)width, numMips,
-				usage, d3dPF, mD3DPool, &textureResources->pCubeTex);
-
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
-		}
-
-		hr = textureResources->pCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&textureResources->pBaseTex);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
-		}
-		
-		// Update final parameters as they may differ from requested ones
-		D3DSURFACE_DESC desc;
-		hr = textureResources->pCubeTex->GetLevelDesc(0, &desc);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
-		}
-
-		setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));		
-	}
-	
-	void D3D9TextureCore::createVolumeTex(IDirect3DDevice9* d3d9Device)
-	{
-		UINT32 width = mProperties.getWidth();
-		UINT32 height = mProperties.getHeight();
-		UINT32 depth = mProperties.getDepth();
-		int texUsage = mProperties.getUsage();
-		UINT32 origNumMips = mProperties.getNumMipmaps();
-		PixelFormat format = mProperties.getFormat();
-		bool hwGamma = mProperties.isHardwareGammaEnabled();
-
-		assert(width > 0 && height > 0 && depth > 0);
-
-		if (texUsage & TU_RENDERTARGET)
-			BS_EXCEPT(RenderingAPIException, "D3D9 Volume texture can not be created as render target !!");
-
-		if (texUsage & TU_DEPTHSTENCIL)
-			BS_EXCEPT(RenderingAPIException, "D3D9 Volume texture can not be created as a depth stencil target !!");
-
-		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
-		if(format != D3D9Mappings::_getPF(d3dPF))
-		{
-			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
-		}
-
-		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
-		DWORD usage = (texUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
-		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
-
-		// Check dynamic textures
-		if (texUsage & TU_DYNAMIC)
-		{
-			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF))
-			{
-				usage |= D3DUSAGE_DYNAMIC;
-				mDynamicTextures = true;
-			}
-			else
-			{
-				mDynamicTextures = false;
-			}
-		}
-
-		// Check sRGB support
-		if (hwGamma)
-		{
-			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF, false);
-			if (texUsage & TU_RENDERTARGET)
-				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF, true);
-		}
-
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& rkCurCaps = device->getD3D9DeviceCaps();			
-
-		// Check if mip map volume textures are supported
-		if (numMips > 1 && !(rkCurCaps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
-		{
-			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
-		}
-
-		determinePool();
-		TextureResources* textureResources;			
-
-		// Get or create new texture resources structure.
-		textureResources = getTextureResources(d3d9Device);
-		if (textureResources != NULL)
-			freeTextureResources(d3d9Device, textureResources);
-		else
-			textureResources = allocateTextureResources(d3d9Device);
-
-		// Create the texture
-		HRESULT hr = D3DXCreateVolumeTexture(d3d9Device, (UINT)width, (UINT)height, (UINT)depth,
-				numMips, usage, d3dPF, mD3DPool, &textureResources->pVolumeTex);
-
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
-		}
-
-		hr = textureResources->pVolumeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void**)&textureResources->pBaseTex);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
-		}
-		
-		// Update final parameters as they may differ from requested ones
-		D3DVOLUME_DESC desc;
-		hr = textureResources->pVolumeTex->GetLevelDesc(0, &desc);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
-		}
-
-		setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, desc.Depth, D3D9Mappings::_getPF(desc.Format));
-	}
-
-	void D3D9TextureCore::setFinalAttributes(IDirect3DDevice9* d3d9Device, TextureResources* textureResources,
-		UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
-	{ 
-		if(width != mProperties.getWidth() || height != mProperties.getHeight() || depth != mProperties.getDepth())
-		{
-			BS_EXCEPT(InternalErrorException, "Wanted and created textures sizes don't match!" \
-				"Width: " + toString(width) + "/" + toString(mProperties.getWidth()) +
-				"Height: " + toString(height) + "/" + toString(mProperties.getHeight()) +
-				"Depth: " + toString(depth) + "/" + toString(mProperties.getDepth()));
-		}
-
-		if(format != mProperties.getFormat())
-		{
-			BS_EXCEPT(InternalErrorException, "Wanted and created texture formats don't match! " + 
-				toString(format) + "/" + toString(mProperties.getFormat()));
-		}
-		
-		createSurfaceList(d3d9Device, textureResources);
-	}
-	
-	D3DTEXTUREFILTERTYPE D3D9TextureCore::getBestFilterMethod(IDirect3DDevice9* d3d9Device)
-	{
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();			
-		
-		DWORD filterCaps = 0;
-
-		switch (mProperties.getTextureType())
-		{
-		case TEX_TYPE_1D:		
-			// Same as 2D
-		case TEX_TYPE_2D:		
-			filterCaps = deviceCaps.TextureFilterCaps;	
-			break;
-		case TEX_TYPE_3D:		
-			filterCaps = deviceCaps.VolumeTextureFilterCaps;	
-			break;
-		case TEX_TYPE_CUBE_MAP:	
-			filterCaps = deviceCaps.CubeTextureFilterCaps;	
-			break;
-		}
-
-		if(filterCaps & D3DPTFILTERCAPS_MINFGAUSSIANQUAD)
-			return D3DTEXF_GAUSSIANQUAD;
-		
-		if(filterCaps & D3DPTFILTERCAPS_MINFPYRAMIDALQUAD)
-			return D3DTEXF_PYRAMIDALQUAD;
-		
-		if(filterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC)
-			return D3DTEXF_ANISOTROPIC;
-		
-		if(filterCaps & D3DPTFILTERCAPS_MINFLINEAR)
-			return D3DTEXF_LINEAR;
-		
-		if(filterCaps & D3DPTFILTERCAPS_MINFPOINT)
-			return D3DTEXF_POINT;
-		
-		return D3DTEXF_POINT;
-	}
-	
-	bool D3D9TextureCore::canUseDynamicTextures(IDirect3DDevice9* d3d9Device, DWORD srcUsage, D3DRESOURCETYPE srcType, 
-		D3DFORMAT srcFormat)
-	{		
-		IDirect3D9* pD3D = nullptr;
-
-		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
-		if (FAILED(hr))
-			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed !!!");
-
-		if (pD3D != nullptr)
-			pD3D->Release();
-	
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
-		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
-
-		hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
-			backBufferFormat, srcUsage | D3DUSAGE_DYNAMIC, srcType, srcFormat);
-
-		return hr == D3D_OK;
-	}
-	
-	bool D3D9TextureCore::canUseHardwareGammaCorrection(IDirect3DDevice9* d3d9Device, DWORD srcUsage, 
-		D3DRESOURCETYPE srcType, D3DFORMAT srcFormat, bool forwriting)
-	{
-		IDirect3D9* pD3D = nullptr;
-
-		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed !!!" );
-		}
-
-		if (pD3D != nullptr)
-			pD3D->Release();
-
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
-		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
-
-		if (forwriting)
-			srcUsage |= D3DUSAGE_QUERY_SRGBWRITE;
-		else
-			srcUsage |= D3DUSAGE_QUERY_SRGBREAD;
-
-		hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
-			backBufferFormat, srcUsage, srcType, srcFormat);
-
-		return hr == D3D_OK;
-	}
-	
-	bool D3D9TextureCore::canAutoGenMipmaps(IDirect3DDevice9* d3d9Device, DWORD srcUsage, D3DRESOURCETYPE srcType, D3DFORMAT srcFormat)
-	{
-		IDirect3D9* pD3D = nullptr;
-
-		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
-		if (FAILED(hr))
-		{
-			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed.");
-		}
-
-		if (pD3D != nullptr)
-			pD3D->Release();
-
-		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
-		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
-
-		if (deviceCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
-		{
-			hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
-					backBufferFormat, srcUsage | D3DUSAGE_AUTOGENMIPMAP, srcType, srcFormat);
-			
-			return hr == D3D_OK;
-		}
-		else
-			return false;
-	}
-	
-	D3DFORMAT D3D9TextureCore::chooseD3DFormat(IDirect3DDevice9* d3d9Device)
-	{		
-		// Choose frame buffer pixel format in case PF_UNKNOWN was requested
-		if(mProperties.getFormat() == PF_UNKNOWN)
-		{	
-			D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
-			
-			if((mProperties.getUsage() & TU_DEPTHSTENCIL) != 0)
-				return device->getDepthStencilFormat();
-			else
-				return device->getBackBufferFormat();		
-		}
-
-		// Choose closest supported D3D format as a D3D format
-		return D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(mProperties.getFormat()));
-	}
-	
-	void D3D9TextureCore::createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources)
-	{
-		int texUsage = mProperties.getUsage();
-		TextureType texType = mProperties.getTextureType();
-		UINT32 numMips = mProperties.getNumMipmaps();
-
-		assert(textureResources != nullptr);
-
-		// Need to know static / dynamic
-		UINT32 usage;
-		if ((texUsage & TU_DYNAMIC) && mDynamicTextures)
-		{
-			usage = GBU_DYNAMIC;
-		}
-		else
-		{
-			usage = GBU_STATIC;
-		}
-
-		if (texUsage & TU_RENDERTARGET)
-		{
-			usage |= TU_RENDERTARGET;
-		}
-		else if (texUsage & TU_DEPTHSTENCIL)
-		{
-			usage |= TU_RENDERTARGET;
-		}
-		
-		UINT32 surfaceCount = static_cast<UINT32>((mProperties.getNumFaces() * (numMips + 1)));
-		bool updateOldList = mSurfaceList.size() == surfaceCount;
-		if(!updateOldList)
-		{			
-			mSurfaceList.clear();
-			for (UINT32 face = 0; face < mProperties.getNumFaces(); face++)
-			{
-				for (UINT32 mip = 0; mip <= numMips; mip++)
-				{
-					mSurfaceList.push_back(bs_shared_ptr_new<D3D9PixelBuffer>((GpuBufferUsage)usage, this));
-				}
-			}
-		}
-
-		IDirect3DSurface9* surface = nullptr;
-		IDirect3DVolume9* volume = nullptr;
-
-		if ((texUsage & TU_RENDERTARGET) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
-		{
-			assert(textureResources->pMultisampleSurface);
-			assert(texType == TEX_TYPE_2D);
-
-			D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[0].get());
-
-			currPixelBuffer->bind(d3d9Device, textureResources->pMultisampleSurface, textureResources->pBaseTex);
-		}
-		else if ((texUsage & TU_DEPTHSTENCIL) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
-		{
-			assert(textureResources->pDepthStencilSurface);
-			assert(texType == TEX_TYPE_2D);
-
-			D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[0].get());
-
-			currPixelBuffer->bind(d3d9Device, textureResources->pDepthStencilSurface, textureResources->pBaseTex);
-		}
-		else
-		{
-			assert(textureResources->pBaseTex);
-
-			UINT32 numCreatedMips = textureResources->pBaseTex->GetLevelCount() - 1;
-			if (numCreatedMips != numMips)
-			{
-				BS_EXCEPT(InternalErrorException, "Number of created and wanted mip map levels doesn't match: " + 
-					toString(numCreatedMips) + "/" + toString(numMips));
-			}
-
-			switch(texType) 
-			{
-			case TEX_TYPE_2D:
-			case TEX_TYPE_1D:
-				assert(textureResources->pNormTex);
-
-				for (UINT32 mip = 0; mip <= numMips; mip++)
-				{
-					if(textureResources->pNormTex->GetSurfaceLevel(static_cast<UINT>(mip), &surface) != D3D_OK)
-						BS_EXCEPT(RenderingAPIException, "Get surface level failed");
-
-					D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[mip].get());
-
-					currPixelBuffer->bind(d3d9Device, surface, textureResources->pBaseTex);
-
-					surface->Release();			
-				}
-
-				break;
-			case TEX_TYPE_CUBE_MAP:
-				assert(textureResources->pCubeTex);
-
-				for(UINT32 face = 0; face < 6; face++)
-				{
-					for (UINT32 mip = 0; mip <= numMips; mip++)
-					{
-						if(textureResources->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, static_cast<UINT>(mip), &surface) != D3D_OK)
-							BS_EXCEPT(RenderingAPIException, "Get cubemap surface failed");
-
-						UINT32 idx = face*(numMips + 1) + mip;
-						D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[idx].get());
-
-						currPixelBuffer->bind(d3d9Device, surface, textureResources->pBaseTex);
-
-						surface->Release();				
-					}				
-				}
-				break;
-			case TEX_TYPE_3D:
-				assert(textureResources->pVolumeTex);
-
-				for (UINT32 mip = 0; mip <= numMips; mip++)
-				{
-					if(textureResources->pVolumeTex->GetVolumeLevel(static_cast<UINT>(mip), &volume) != D3D_OK)
-						BS_EXCEPT(RenderingAPIException, "Get volume level failed");	
-
-					D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[mip].get());
-					currPixelBuffer->bind(d3d9Device, volume, textureResources->pBaseTex);
-
-					volume->Release();
-				}
-				break;
-			};		
-		}		
-	}
-
-	PixelBufferPtr D3D9TextureCore::getBuffer(UINT32 face, UINT32 mipmap) 
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if(face >= mProperties.getNumFaces())
-			BS_EXCEPT(InvalidParametersException, "A three dimensional cube has six faces");
-		if (mipmap > mProperties.getNumMipmaps())
-			BS_EXCEPT(InvalidParametersException, "Mipmap index out of range");
-
-		UINT32 idx = face*(mProperties.getNumMipmaps() + 1) + mipmap;
-
-		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
-		TextureResources* textureResources = getTextureResources(d3d9Device);
-		if (textureResources == nullptr || textureResources->pBaseTex == nullptr)
-		{				
-			createInternalResources(d3d9Device);
-			textureResources = getTextureResources(d3d9Device);			
-		}
-	
-		assert(textureResources != nullptr);
-		assert(idx < mSurfaceList.size());
-		return mSurfaceList[idx];
-	}
-
-	bool D3D9TextureCore::useDefaultPool()
-	{
-		int usage = mProperties.getUsage();
-		return (usage & TU_RENDERTARGET) || (usage & TU_DEPTHSTENCIL) || ((usage & TU_DYNAMIC) && mDynamicTextures);
-	}
-	
-	void D3D9TextureCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device) 
-	{		
-		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
-
-		if (D3D9RenderAPI::getResourceManager()->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES)
-			createInternalResources(d3d9Device);
-	}
-
-	void D3D9TextureCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device) 
-	{				
-		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
-
-		auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
-
-		if (iterFind != mMapDeviceToTextureResources.end())
-		{			
-			TextureResources* textureResource = iterFind->second;
-
-			for(unsigned int i = 0; i < mSurfaceList.size(); ++i)
-			{
-				D3D9PixelBuffer* pixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[i].get());
-
-				pixelBuffer->destroyBufferResources(d3d9Device);			
-			}
-
-			freeTextureResources(d3d9Device, textureResource);
-
-			if(textureResource != nullptr)
-				bs_delete(textureResource);
-
-			mMapDeviceToTextureResources.erase(iterFind);
-		}	
-	}
-
-	void D3D9TextureCore::notifyOnDeviceLost(IDirect3DDevice9* d3d9Device) 
-	{		
-		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
-
-		if(mD3DPool == D3DPOOL_DEFAULT)
-		{
-			auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
-
-			if (iterFind != mMapDeviceToTextureResources.end())
-			{
-				TextureResources* textureResource = iterFind->second;				
-				freeTextureResources(d3d9Device, textureResource);
-			}					
-		}		
-	}
-
-	void D3D9TextureCore::notifyOnDeviceReset(IDirect3DDevice9* d3d9Device) 
-	{		
-		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
-
-		if(mD3DPool == D3DPOOL_DEFAULT)
-		{			
-			createInternalResources(d3d9Device);
-		}
-	}
-
-	IDirect3DBaseTexture9* D3D9TextureCore::getTexture_internal()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		TextureResources* textureResources;			
-		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
-			
-		textureResources = getTextureResources(d3d9Device);		
-		if (textureResources == nullptr || textureResources->pBaseTex == nullptr)
-		{			
-			createInternalResources(d3d9Device);
-			textureResources = getTextureResources(d3d9Device);			
-		}
-
-		assert(textureResources); 
-		assert(textureResources->pBaseTex); 
-
-		return textureResources->pBaseTex;
-	}
-
-	IDirect3DTexture9* D3D9TextureCore::getNormTexture_internal()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		TextureResources* textureResources;
-		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
-		
-		textureResources = getTextureResources(d3d9Device);		
-		if (textureResources == nullptr || textureResources->pNormTex == nullptr)
-		{
-			createInternalResources(d3d9Device);
-			textureResources = getTextureResources(d3d9Device);			
-		}
-		assert(textureResources); 
-		assert(textureResources->pNormTex); 
-
-		return textureResources->pNormTex;
-	}
-
-	IDirect3DCubeTexture9* D3D9TextureCore::getCubeTexture_internal()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		TextureResources* textureResources;
-		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
-		
-		textureResources = getTextureResources(d3d9Device);		
-		if (textureResources == nullptr || textureResources->pCubeTex)
-		{
-			createInternalResources(d3d9Device);
-			textureResources = getTextureResources(d3d9Device);			
-		}
-
-		assert(textureResources); 
-		assert(textureResources->pCubeTex); 
-
-		return textureResources->pCubeTex;
-	}	
+#include "BsCoreThread.h"
+#include "BsD3D9Texture.h"
+#include "BsD3D9PixelBuffer.h"
+#include "BsException.h"
+#include "BsBitwise.h"
+#include "BsD3D9Mappings.h"
+#include "BsD3D9RenderAPI.h"
+#include "BsD3D9TextureManager.h"
+#include "BsD3D9Device.h"
+#include "BsD3D9DeviceManager.h"
+#include "BsD3D9ResourceManager.h"
+#include "BsRenderStats.h"
+#include "BsPixelData.h"
+
+namespace BansheeEngine 
+{
+	D3D9TextureCore::D3D9TextureCore(TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, UINT32 numMipmaps,
+		PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initialData)
+		:TextureCore(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount, initialData),
+		mD3DPool(D3DPOOL_MANAGED), mDynamicTextures(false), mHwGammaReadSupported(false), mHwGammaWriteSupported(false), 
+		mMultisampleType(D3DMULTISAMPLE_NONE), mMultisampleQuality(0), mIsBindableAsShaderResource(true)
+	{
+
+	}
+	
+	D3D9TextureCore::~D3D9TextureCore()
+	{	
+		THROW_IF_NOT_CORE_THREAD;
+
+		for (auto& resPair : mMapDeviceToTextureResources)
+		{
+			TextureResources* textureResource = resPair.second;
+
+			freeTextureResources(resPair.first, textureResource);
+		}
+
+		for (auto& resPair : mMapDeviceToTextureResources)
+		{
+			TextureResources* textureResource = resPair.second;
+
+			if (textureResource != nullptr)
+				bs_delete(textureResource);
+		}
+
+		mMapDeviceToTextureResources.clear();
+		mSurfaceList.clear();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
+	}
+
+	void D3D9TextureCore::initialize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		for (UINT32 i = 0; i < D3D9RenderAPI::getResourceCreationDeviceCount(); ++i)
+		{
+			IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getResourceCreationDevice(i);
+
+			createInternalResources(d3d9Device);
+		}
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
+		TextureCore::initialize();
+	}
+
+	PixelData D3D9TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		if(mLockedBuffer != nullptr)
+			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
+
+		if (mProperties.getUsage() == TU_DEPTHSTENCIL)
+			BS_EXCEPT(InternalErrorException, "Cannot lock a depth stencil texture.");
+
+		UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
+		UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
+		UINT32 mipDepth = std::max(1u, mProperties.getDepth() >> mipLevel);
+
+		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
+
+		mLockedBuffer = getBuffer(face, mipLevel);
+		lockedArea.setExternalBuffer((UINT8*)mLockedBuffer->lock(options));
+
+		return lockedArea;
+	}
+	
+	void D3D9TextureCore::unlockImpl()
+	{
+		if(mLockedBuffer == nullptr)
+			BS_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
+
+		mLockedBuffer->unlock();
+		mLockedBuffer = nullptr;
+	}
+
+	void D3D9TextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		if (mProperties.getUsage() == TU_DEPTHSTENCIL || mProperties.getUsage() == TU_RENDERTARGET) // Render targets cannot be locked normally
+		{
+			IDirect3DDevice9* device = D3D9RenderAPI::getActiveD3D9Device();
+
+			D3D9PixelBuffer* sourceBuffer = static_cast<D3D9PixelBuffer*>(getBuffer(face, mipLevel).get());
+			
+			UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
+			UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
+			D3DFORMAT format = chooseD3DFormat(device);
+
+			// Note: I'm allocating and releasing a texture every time we read.
+			// I might consider adding a flag to keep this texture permanent which would make reading
+			// faster but at the cost of double the memory.
+
+			IDirect3DTexture9* stagingTexture = nullptr; 
+			HRESULT hr = D3DXCreateTexture(device, (UINT)mipWidth, (UINT)mipHeight, 1,
+				0, format, D3DPOOL_SYSTEMMEM, &stagingTexture);
+
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription(hr);
+				BS_EXCEPT(RenderingAPIException, "Failed to create a texture: " + msg);
+			}
+
+			IDirect3DSurface9* stagingSurface = nullptr;
+			hr = stagingTexture->GetSurfaceLevel(0, &stagingSurface);
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription(hr);
+				BS_EXCEPT(RenderingAPIException, "Failed to retrieve a texture surface: " + msg);
+			}
+
+			hr = device->GetRenderTargetData(sourceBuffer->getSurface(device), stagingSurface);
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription(hr);
+				BS_EXCEPT(RenderingAPIException, "Failed to retrieve render target data: " + msg);
+			}
+
+			PixelData myData(mipWidth, mipHeight, 1, mProperties.getFormat());
+
+			D3DLOCKED_RECT lrect;
+			hr = stagingSurface->LockRect(&lrect, nullptr, D3DLOCK_READONLY);
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription(hr);
+				BS_EXCEPT(RenderingAPIException, "Failed to lock surface: " + msg);
+			}
+
+			D3D9PixelBuffer::initPixelDataFromD3DLock(myData, lrect);
+
+#if BS_DEBUG_MODE
+			if (dest.getConsecutiveSize() != myData.getConsecutiveSize())
+				BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+#endif
+
+			PixelUtil::bulkPixelConversion(myData, dest);
+
+			hr = stagingSurface->UnlockRect();
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription(hr);
+				BS_EXCEPT(RenderingAPIException, "Failed to unlock surface: " + msg);
+			}
+
+			SAFE_RELEASE(stagingSurface);
+			SAFE_RELEASE(stagingTexture);
+		}
+		else
+		{
+			PixelData myData = lock(GBL_READ_ONLY, mipLevel, face);
+
+#if BS_DEBUG_MODE
+			if (dest.getConsecutiveSize() != myData.getConsecutiveSize())
+			{
+				unlock();
+				BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+			}
+#endif
+
+			PixelUtil::bulkPixelConversion(myData, dest);
+
+			unlock();
+		}
+	}
+
+	void D3D9TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		if (mProperties.getUsage() == TU_DYNAMIC || mProperties.getUsage() == TU_STATIC)
+		{
+			PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mipLevel, face);
+			PixelUtil::bulkPixelConversion(src, myData);
+			unlock();
+		}
+		else
+		{
+			BS_EXCEPT(RenderingAPIException, "Trying to write into a buffer with unsupported usage: " + toString(mProperties.getUsage()));
+		}
+	}
+	
+	void D3D9TextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		TextureType texType = mProperties.getTextureType();
+
+		if (texType == TEX_TYPE_1D || texType == TEX_TYPE_3D)
+			BS_EXCEPT(NotImplementedException, "Copy not implemented for 1D and 3D textures yet.");
+
+        HRESULT hr;
+		D3D9TextureCore* other = static_cast<D3D9TextureCore*>(target.get());
+
+		for (auto& resPair : mMapDeviceToTextureResources)
+		{
+			TextureResources* srcTextureResource = resPair.second;
+			TextureResources* dstTextureResource = other->getTextureResources(resPair.first);
+
+			IDirect3DSurface9 *sourceSurface = nullptr;
+			IDirect3DSurface9 *destSurface = nullptr;
+
+			if (texType == TEX_TYPE_2D && srcTextureResource->pNormTex != nullptr && dstTextureResource->pNormTex != nullptr)
+			{			
+				if(FAILED(hr = srcTextureResource->pNormTex->GetSurfaceLevel(srcMipLevel, &sourceSurface)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
+				}
+
+				if(FAILED(hr = dstTextureResource->pNormTex->GetSurfaceLevel(destMipLevel, &destSurface)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
+				}
+			}
+			else if (texType == TEX_TYPE_CUBE_MAP && srcTextureResource->pCubeTex != nullptr && dstTextureResource->pCubeTex != nullptr)
+			{				
+				IDirect3DSurface9 *sourceSurface = nullptr;
+				if (FAILED(hr = srcTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)srcFace, srcMipLevel, &sourceSurface)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve source surface for copy: " + msg);
+				}
+
+				IDirect3DSurface9 *destSurface = nullptr;
+				if (FAILED(hr = dstTextureResource->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)destFace, destMipLevel, &destSurface)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "Cannot retrieve destination surface for copy: " + msg);
+				}
+			}
+
+			if (sourceSurface != nullptr && destSurface != nullptr)
+			{
+				D3DSURFACE_DESC desc;
+
+				sourceSurface->GetDesc(&desc);
+				if (desc.Pool != D3DPOOL_DEFAULT)
+					BS_EXCEPT(InvalidStateException, "Source surface must be in the default pool.");
+
+				destSurface->GetDesc(&desc);
+				if (desc.Pool != D3DPOOL_DEFAULT)
+					BS_EXCEPT(InvalidStateException, "Destination surface must be in the default pool.");
+
+				if (FAILED(hr = resPair.first->StretchRect(sourceSurface, NULL, destSurface, NULL, D3DTEXF_NONE)))
+				{
+					String msg = DXGetErrorDescription(hr);
+					BS_EXCEPT(RenderingAPIException, "StretchRect failed during copy: " + msg);
+				}
+			}
+
+			SAFE_RELEASE(sourceSurface);
+			SAFE_RELEASE(destSurface);
+		}		
+	}
+	
+	D3D9TextureCore::TextureResources* D3D9TextureCore::getTextureResources(IDirect3DDevice9* d3d9Device)
+	{		
+		auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
+
+		if (iterFind == mMapDeviceToTextureResources.end())		
+			return nullptr;		
+		
+		return iterFind->second;
+	}
+
+	D3D9TextureCore::TextureResources* D3D9TextureCore::allocateTextureResources(IDirect3DDevice9* d3d9Device)
+	{
+		assert(mMapDeviceToTextureResources.find(d3d9Device) == mMapDeviceToTextureResources.end());
+
+		TextureResources* textureResources = bs_new<TextureResources>();
+
+		textureResources->pNormTex = nullptr;
+		textureResources->pCubeTex = nullptr;
+		textureResources->pVolumeTex = nullptr;
+		textureResources->pBaseTex = nullptr;
+		textureResources->pMultisampleSurface = nullptr;
+		textureResources->pDepthStencilSurface = nullptr;
+
+		mMapDeviceToTextureResources[d3d9Device] = textureResources;
+
+		return textureResources;
+	}
+	
+	void D3D9TextureCore::freeTextureResources(IDirect3DDevice9* d3d9Device, D3D9TextureCore::TextureResources* textureResources)
+	{		
+		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
+
+		// Release surfaces from each mip level.
+		for(unsigned int i = 0; i < mSurfaceList.size(); ++i)
+		{
+			D3D9PixelBuffer* pixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[i].get());
+
+			pixelBuffer->releaseSurfaces(d3d9Device);			
+		}
+		
+		// Release the rest of the resources.
+		SAFE_RELEASE(textureResources->pBaseTex);
+		SAFE_RELEASE(textureResources->pNormTex);
+		SAFE_RELEASE(textureResources->pCubeTex);
+		SAFE_RELEASE(textureResources->pVolumeTex);
+		SAFE_RELEASE(textureResources->pMultisampleSurface);
+		SAFE_RELEASE(textureResources->pDepthStencilSurface);
+	}
+	
+	UINT32 D3D9TextureCore::calculateSize() const
+	{
+		UINT32 instanceSize = mProperties.getNumFaces() * 
+			PixelUtil::getMemorySize(mProperties.getWidth(), mProperties.getHeight(), 
+			mProperties.getDepth(), mProperties.getFormat());
+
+		return instanceSize * (UINT32)mMapDeviceToTextureResources.size();
+	}
+	
+	void D3D9TextureCore::determinePool()
+	{
+		if (useDefaultPool())
+			mD3DPool = D3DPOOL_DEFAULT;
+		else
+			mD3DPool = D3DPOOL_MANAGED;
+	}
+	
+	void D3D9TextureCore::createInternalResources(IDirect3DDevice9* d3d9Device)
+	{		
+		switch (mProperties.getTextureType())
+		{
+		case TEX_TYPE_1D:
+		case TEX_TYPE_2D:
+			createNormTex(d3d9Device);
+			break;
+		case TEX_TYPE_CUBE_MAP:
+			createCubeTex(d3d9Device);
+			break;
+		case TEX_TYPE_3D:
+			createVolumeTex(d3d9Device);
+			break;
+		default:
+			BS_EXCEPT(InternalErrorException, "Unknown texture type.");
+		}
+	}
+
+	void D3D9TextureCore::createNormTex(IDirect3DDevice9* d3d9Device)
+	{
+		UINT32 width = mProperties.getWidth();
+		UINT32 height = mProperties.getHeight();
+		int texUsage = mProperties.getUsage();
+		UINT32 origNumMips = mProperties.getNumMipmaps();
+		PixelFormat format = mProperties.getFormat();
+		bool hwGamma = mProperties.isHardwareGammaEnabled();
+		UINT32 sampleCount = mProperties.getMultisampleCount();
+
+		assert(width > 0 || height > 0);
+
+		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
+		if (format != D3D9Mappings::_getPF(d3dPF))
+		{
+			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
+		}
+
+		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
+		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
+
+		DWORD usage = 0;
+		if ((texUsage & TU_RENDERTARGET) != 0)
+			usage = D3DUSAGE_RENDERTARGET;
+		else if ((texUsage & TU_DEPTHSTENCIL) != 0)
+			usage = D3DUSAGE_DEPTHSTENCIL;
+
+		// Check dynamic textures
+		if (texUsage & TU_DYNAMIC)
+		{
+			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF))
+			{
+				usage |= D3DUSAGE_DYNAMIC;
+				mDynamicTextures = true;
+			}
+			else
+			{
+				mDynamicTextures = false;
+			}
+		}
+
+		// Check sRGB support
+		if (hwGamma)
+		{
+			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF, false);
+			if (texUsage & TU_RENDERTARGET)
+				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_TEXTURE, d3dPF, true);
+		}
+
+		// Check multisample level
+		if ((texUsage & TU_RENDERTARGET) != 0 || (texUsage & TU_DEPTHSTENCIL) != 0)
+		{
+			D3D9RenderAPI* rsys = static_cast<D3D9RenderAPI*>(BansheeEngine::RenderAPICore::instancePtr());
+			rsys->determineMultisampleSettings(d3d9Device, sampleCount, d3dPF, false, &mMultisampleType, &mMultisampleQuality);
+		}
+		else
+		{
+			mMultisampleType = D3DMULTISAMPLE_NONE;
+			mMultisampleQuality = 0;
+		}
+
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& rkCurCaps = device->getD3D9DeviceCaps();			
+
+		// Check if mip maps are supported on hardware
+		if (numMips > 1 && (!(rkCurCaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) || (texUsage & TU_RENDERTARGET) != 0 || (texUsage & TU_DEPTHSTENCIL) != 0))
+		{
+			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
+		}
+
+		determinePool();
+		TextureResources* textureResources;			
+	
+		// Get or create new texture resources structure.
+		textureResources = getTextureResources(d3d9Device);
+		if (textureResources != NULL)
+			freeTextureResources(d3d9Device, textureResources);
+		else
+			textureResources = allocateTextureResources(d3d9Device);
+
+		if ((texUsage & TU_RENDERTARGET) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
+		{
+			// Create AA surface
+			HRESULT hr = d3d9Device->CreateRenderTarget(width, height, d3dPF, 
+				mMultisampleType, mMultisampleQuality,
+				FALSE,
+				&textureResources->pMultisampleSurface, NULL);
+
+			if (FAILED(hr))
+				BS_EXCEPT(RenderingAPIException, "Unable to create AA render target: " + String(DXGetErrorDescription(hr)));
+
+			D3DSURFACE_DESC desc;
+			hr = textureResources->pMultisampleSurface->GetDesc(&desc);
+			if (FAILED(hr))
+			{
+				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
+			}
+
+			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
+
+			mIsBindableAsShaderResource = false; // Cannot bind AA surfaces
+		}
+		else if ((texUsage & TU_DEPTHSTENCIL) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
+		{
+			// Create AA depth stencil surface
+			HRESULT hr = d3d9Device->CreateDepthStencilSurface(width, height, d3dPF, 
+				mMultisampleType, mMultisampleQuality,
+				FALSE, 
+				&textureResources->pDepthStencilSurface, NULL);
+
+			if (FAILED(hr))
+				BS_EXCEPT(RenderingAPIException, "Unable to create AA depth stencil render target: " + String(DXGetErrorDescription(hr)));
+
+			// Update final parameters as they may differ from requested ones
+			D3DSURFACE_DESC desc;
+			hr = textureResources->pDepthStencilSurface->GetDesc(&desc);
+			if (FAILED(hr))
+			{
+				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
+			}
+
+			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
+
+			mIsBindableAsShaderResource = false; // Cannot bind AA depth buffer
+		}
+		else
+		{
+			// Create normal texture
+			HRESULT hr = D3DXCreateTexture(d3d9Device, (UINT)width, (UINT)height, numMips,
+				usage, d3dPF, mD3DPool, &textureResources->pNormTex);
+
+			if (FAILED(hr))
+			{
+				BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
+			}
+
+			hr = textureResources->pNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&textureResources->pBaseTex);
+			if (FAILED(hr))
+			{
+				BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
+			}
+
+			// Update final parameters as they may differ from requested ones
+			D3DSURFACE_DESC desc;
+			hr = textureResources->pNormTex->GetLevelDesc(0, &desc);
+			if (FAILED(hr))
+			{
+				BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
+			}
+
+			setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
+		}
+	}
+	
+	void D3D9TextureCore::createCubeTex(IDirect3DDevice9* d3d9Device)
+	{
+		UINT32 width = mProperties.getWidth();
+		UINT32 height = mProperties.getHeight();
+		int texUsage = mProperties.getUsage();
+		UINT32 origNumMips = mProperties.getNumMipmaps();
+		PixelFormat format = mProperties.getFormat();
+		bool hwGamma = mProperties.isHardwareGammaEnabled();
+
+		assert(width > 0 || height > 0);
+
+		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
+		if (format != D3D9Mappings::_getPF(d3dPF))
+		{
+			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
+		}
+
+		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
+		DWORD usage = (texUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
+		usage |= (texUsage & TU_DEPTHSTENCIL) ? D3DUSAGE_DEPTHSTENCIL : 0;
+
+		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
+
+		// Check dynamic textures
+		if (texUsage & TU_DYNAMIC)
+		{
+			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF))
+			{
+				usage |= D3DUSAGE_DYNAMIC;
+				mDynamicTextures = true;
+			}
+			else
+			{
+				mDynamicTextures = false;
+			}
+		}
+
+		// Check sRGB support
+		if (hwGamma)
+		{
+			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF, false);
+			if (texUsage & TU_RENDERTARGET)
+				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_CUBETEXTURE, d3dPF, true);
+		}
+
+		// No multisampling on cube textures
+		mMultisampleType = D3DMULTISAMPLE_NONE;
+		mMultisampleQuality = 0;
+
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();			
+		
+		// Check if mip map cube textures are supported
+		if (numMips > 1 && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP))
+		{
+			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
+		}
+
+		determinePool();
+		TextureResources* textureResources;			
+
+		// Get or create new texture resources structure.
+		textureResources = getTextureResources(d3d9Device);
+		if (textureResources != NULL)
+			freeTextureResources(d3d9Device, textureResources);
+		else
+			textureResources = allocateTextureResources(d3d9Device);
+
+		// Create the texture
+		HRESULT hr = D3DXCreateCubeTexture(d3d9Device, (UINT)width, numMips,
+				usage, d3dPF, mD3DPool, &textureResources->pCubeTex);
+
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
+		}
+
+		hr = textureResources->pCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&textureResources->pBaseTex);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
+		}
+		
+		// Update final parameters as they may differ from requested ones
+		D3DSURFACE_DESC desc;
+		hr = textureResources->pCubeTex->GetLevelDesc(0, &desc);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
+		}
+
+		setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));		
+	}
+	
+	void D3D9TextureCore::createVolumeTex(IDirect3DDevice9* d3d9Device)
+	{
+		UINT32 width = mProperties.getWidth();
+		UINT32 height = mProperties.getHeight();
+		UINT32 depth = mProperties.getDepth();
+		int texUsage = mProperties.getUsage();
+		UINT32 origNumMips = mProperties.getNumMipmaps();
+		PixelFormat format = mProperties.getFormat();
+		bool hwGamma = mProperties.isHardwareGammaEnabled();
+
+		assert(width > 0 && height > 0 && depth > 0);
+
+		if (texUsage & TU_RENDERTARGET)
+			BS_EXCEPT(RenderingAPIException, "D3D9 Volume texture can not be created as render target !!");
+
+		if (texUsage & TU_DEPTHSTENCIL)
+			BS_EXCEPT(RenderingAPIException, "D3D9 Volume texture can not be created as a depth stencil target !!");
+
+		D3DFORMAT d3dPF = chooseD3DFormat(d3d9Device);
+		if(format != D3D9Mappings::_getPF(d3dPF))
+		{
+			BS_EXCEPT(RenderingAPIException, "Provided pixel format is not supported by the driver: " + toString(format));
+		}
+
+		// Use D3DX to help us create the texture, this way it can adjust any relevant sizes
+		DWORD usage = (texUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
+		UINT numMips = (origNumMips == MIP_UNLIMITED) ? D3DX_DEFAULT : origNumMips + 1;
+
+		// Check dynamic textures
+		if (texUsage & TU_DYNAMIC)
+		{
+			if (canUseDynamicTextures(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF))
+			{
+				usage |= D3DUSAGE_DYNAMIC;
+				mDynamicTextures = true;
+			}
+			else
+			{
+				mDynamicTextures = false;
+			}
+		}
+
+		// Check sRGB support
+		if (hwGamma)
+		{
+			mHwGammaReadSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF, false);
+			if (texUsage & TU_RENDERTARGET)
+				mHwGammaWriteSupported = canUseHardwareGammaCorrection(d3d9Device, usage, D3DRTYPE_VOLUMETEXTURE, d3dPF, true);
+		}
+
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& rkCurCaps = device->getD3D9DeviceCaps();			
+
+		// Check if mip map volume textures are supported
+		if (numMips > 1 && !(rkCurCaps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
+		{
+			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: 0");
+		}
+
+		determinePool();
+		TextureResources* textureResources;			
+
+		// Get or create new texture resources structure.
+		textureResources = getTextureResources(d3d9Device);
+		if (textureResources != NULL)
+			freeTextureResources(d3d9Device, textureResources);
+		else
+			textureResources = allocateTextureResources(d3d9Device);
+
+		// Create the texture
+		HRESULT hr = D3DXCreateVolumeTexture(d3d9Device, (UINT)width, (UINT)height, (UINT)depth,
+				numMips, usage, d3dPF, mD3DPool, &textureResources->pVolumeTex);
+
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Error creating texture: " + String(DXGetErrorDescription(hr)));
+		}
+
+		hr = textureResources->pVolumeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void**)&textureResources->pBaseTex);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Can't get base texture: " + String(DXGetErrorDescription(hr)));
+		}
+		
+		// Update final parameters as they may differ from requested ones
+		D3DVOLUME_DESC desc;
+		hr = textureResources->pVolumeTex->GetLevelDesc(0, &desc);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(RenderingAPIException, "Can't get texture description: " + String(DXGetErrorDescription(hr)));
+		}
+
+		setFinalAttributes(d3d9Device, textureResources, desc.Width, desc.Height, desc.Depth, D3D9Mappings::_getPF(desc.Format));
+	}
+
+	void D3D9TextureCore::setFinalAttributes(IDirect3DDevice9* d3d9Device, TextureResources* textureResources,
+		UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
+	{ 
+		if(width != mProperties.getWidth() || height != mProperties.getHeight() || depth != mProperties.getDepth())
+		{
+			BS_EXCEPT(InternalErrorException, "Wanted and created textures sizes don't match!" \
+				"Width: " + toString(width) + "/" + toString(mProperties.getWidth()) +
+				"Height: " + toString(height) + "/" + toString(mProperties.getHeight()) +
+				"Depth: " + toString(depth) + "/" + toString(mProperties.getDepth()));
+		}
+
+		if(format != mProperties.getFormat())
+		{
+			BS_EXCEPT(InternalErrorException, "Wanted and created texture formats don't match! " + 
+				toString(format) + "/" + toString(mProperties.getFormat()));
+		}
+		
+		createSurfaceList(d3d9Device, textureResources);
+	}
+	
+	D3DTEXTUREFILTERTYPE D3D9TextureCore::getBestFilterMethod(IDirect3DDevice9* d3d9Device)
+	{
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();			
+		
+		DWORD filterCaps = 0;
+
+		switch (mProperties.getTextureType())
+		{
+		case TEX_TYPE_1D:		
+			// Same as 2D
+		case TEX_TYPE_2D:		
+			filterCaps = deviceCaps.TextureFilterCaps;	
+			break;
+		case TEX_TYPE_3D:		
+			filterCaps = deviceCaps.VolumeTextureFilterCaps;	
+			break;
+		case TEX_TYPE_CUBE_MAP:	
+			filterCaps = deviceCaps.CubeTextureFilterCaps;	
+			break;
+		}
+
+		if(filterCaps & D3DPTFILTERCAPS_MINFGAUSSIANQUAD)
+			return D3DTEXF_GAUSSIANQUAD;
+		
+		if(filterCaps & D3DPTFILTERCAPS_MINFPYRAMIDALQUAD)
+			return D3DTEXF_PYRAMIDALQUAD;
+		
+		if(filterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC)
+			return D3DTEXF_ANISOTROPIC;
+		
+		if(filterCaps & D3DPTFILTERCAPS_MINFLINEAR)
+			return D3DTEXF_LINEAR;
+		
+		if(filterCaps & D3DPTFILTERCAPS_MINFPOINT)
+			return D3DTEXF_POINT;
+		
+		return D3DTEXF_POINT;
+	}
+	
+	bool D3D9TextureCore::canUseDynamicTextures(IDirect3DDevice9* d3d9Device, DWORD srcUsage, D3DRESOURCETYPE srcType, 
+		D3DFORMAT srcFormat)
+	{		
+		IDirect3D9* pD3D = nullptr;
+
+		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
+		if (FAILED(hr))
+			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed !!!");
+
+		if (pD3D != nullptr)
+			pD3D->Release();
+	
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
+		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
+
+		hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
+			backBufferFormat, srcUsage | D3DUSAGE_DYNAMIC, srcType, srcFormat);
+
+		return hr == D3D_OK;
+	}
+	
+	bool D3D9TextureCore::canUseHardwareGammaCorrection(IDirect3DDevice9* d3d9Device, DWORD srcUsage, 
+		D3DRESOURCETYPE srcType, D3DFORMAT srcFormat, bool forwriting)
+	{
+		IDirect3D9* pD3D = nullptr;
+
+		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed !!!" );
+		}
+
+		if (pD3D != nullptr)
+			pD3D->Release();
+
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
+		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
+
+		if (forwriting)
+			srcUsage |= D3DUSAGE_QUERY_SRGBWRITE;
+		else
+			srcUsage |= D3DUSAGE_QUERY_SRGBREAD;
+
+		hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
+			backBufferFormat, srcUsage, srcType, srcFormat);
+
+		return hr == D3D_OK;
+	}
+	
+	bool D3D9TextureCore::canAutoGenMipmaps(IDirect3DDevice9* d3d9Device, DWORD srcUsage, D3DRESOURCETYPE srcType, D3DFORMAT srcFormat)
+	{
+		IDirect3D9* pD3D = nullptr;
+
+		HRESULT hr = d3d9Device->GetDirect3D(&pD3D);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(InvalidParametersException, "GetDirect3D failed.");
+		}
+
+		if (pD3D != nullptr)
+			pD3D->Release();
+
+		D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+		const D3DCAPS9& deviceCaps = device->getD3D9DeviceCaps();						
+		D3DFORMAT backBufferFormat = device->getBackBufferFormat();
+
+		if (deviceCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
+		{
+			hr = pD3D->CheckDeviceFormat(deviceCaps.AdapterOrdinal, deviceCaps.DeviceType, 
+					backBufferFormat, srcUsage | D3DUSAGE_AUTOGENMIPMAP, srcType, srcFormat);
+			
+			return hr == D3D_OK;
+		}
+		else
+			return false;
+	}
+	
+	D3DFORMAT D3D9TextureCore::chooseD3DFormat(IDirect3DDevice9* d3d9Device)
+	{		
+		// Choose frame buffer pixel format in case PF_UNKNOWN was requested
+		if(mProperties.getFormat() == PF_UNKNOWN)
+		{	
+			D3D9Device* device = D3D9RenderAPI::getDeviceManager()->getDeviceFromD3D9Device(d3d9Device);
+			
+			if((mProperties.getUsage() & TU_DEPTHSTENCIL) != 0)
+				return device->getDepthStencilFormat();
+			else
+				return device->getBackBufferFormat();		
+		}
+
+		// Choose closest supported D3D format as a D3D format
+		return D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(mProperties.getFormat()));
+	}
+	
+	void D3D9TextureCore::createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources)
+	{
+		int texUsage = mProperties.getUsage();
+		TextureType texType = mProperties.getTextureType();
+		UINT32 numMips = mProperties.getNumMipmaps();
+
+		assert(textureResources != nullptr);
+
+		// Need to know static / dynamic
+		UINT32 usage;
+		if ((texUsage & TU_DYNAMIC) && mDynamicTextures)
+		{
+			usage = GBU_DYNAMIC;
+		}
+		else
+		{
+			usage = GBU_STATIC;
+		}
+
+		if (texUsage & TU_RENDERTARGET)
+		{
+			usage |= TU_RENDERTARGET;
+		}
+		else if (texUsage & TU_DEPTHSTENCIL)
+		{
+			usage |= TU_RENDERTARGET;
+		}
+		
+		UINT32 surfaceCount = static_cast<UINT32>((mProperties.getNumFaces() * (numMips + 1)));
+		bool updateOldList = mSurfaceList.size() == surfaceCount;
+		if(!updateOldList)
+		{			
+			mSurfaceList.clear();
+			for (UINT32 face = 0; face < mProperties.getNumFaces(); face++)
+			{
+				for (UINT32 mip = 0; mip <= numMips; mip++)
+				{
+					mSurfaceList.push_back(bs_shared_ptr_new<D3D9PixelBuffer>((GpuBufferUsage)usage, this));
+				}
+			}
+		}
+
+		IDirect3DSurface9* surface = nullptr;
+		IDirect3DVolume9* volume = nullptr;
+
+		if ((texUsage & TU_RENDERTARGET) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
+		{
+			assert(textureResources->pMultisampleSurface);
+			assert(texType == TEX_TYPE_2D);
+
+			D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[0].get());
+
+			currPixelBuffer->bind(d3d9Device, textureResources->pMultisampleSurface, textureResources->pBaseTex);
+		}
+		else if ((texUsage & TU_DEPTHSTENCIL) != 0 && (mMultisampleType != D3DMULTISAMPLE_NONE))
+		{
+			assert(textureResources->pDepthStencilSurface);
+			assert(texType == TEX_TYPE_2D);
+
+			D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[0].get());
+
+			currPixelBuffer->bind(d3d9Device, textureResources->pDepthStencilSurface, textureResources->pBaseTex);
+		}
+		else
+		{
+			assert(textureResources->pBaseTex);
+
+			UINT32 numCreatedMips = textureResources->pBaseTex->GetLevelCount() - 1;
+			if (numCreatedMips != numMips)
+			{
+				BS_EXCEPT(InternalErrorException, "Number of created and wanted mip map levels doesn't match: " + 
+					toString(numCreatedMips) + "/" + toString(numMips));
+			}
+
+			switch(texType) 
+			{
+			case TEX_TYPE_2D:
+			case TEX_TYPE_1D:
+				assert(textureResources->pNormTex);
+
+				for (UINT32 mip = 0; mip <= numMips; mip++)
+				{
+					if(textureResources->pNormTex->GetSurfaceLevel(static_cast<UINT>(mip), &surface) != D3D_OK)
+						BS_EXCEPT(RenderingAPIException, "Get surface level failed");
+
+					D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[mip].get());
+
+					currPixelBuffer->bind(d3d9Device, surface, textureResources->pBaseTex);
+
+					surface->Release();			
+				}
+
+				break;
+			case TEX_TYPE_CUBE_MAP:
+				assert(textureResources->pCubeTex);
+
+				for(UINT32 face = 0; face < 6; face++)
+				{
+					for (UINT32 mip = 0; mip <= numMips; mip++)
+					{
+						if(textureResources->pCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, static_cast<UINT>(mip), &surface) != D3D_OK)
+							BS_EXCEPT(RenderingAPIException, "Get cubemap surface failed");
+
+						UINT32 idx = face*(numMips + 1) + mip;
+						D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[idx].get());
+
+						currPixelBuffer->bind(d3d9Device, surface, textureResources->pBaseTex);
+
+						surface->Release();				
+					}				
+				}
+				break;
+			case TEX_TYPE_3D:
+				assert(textureResources->pVolumeTex);
+
+				for (UINT32 mip = 0; mip <= numMips; mip++)
+				{
+					if(textureResources->pVolumeTex->GetVolumeLevel(static_cast<UINT>(mip), &volume) != D3D_OK)
+						BS_EXCEPT(RenderingAPIException, "Get volume level failed");	
+
+					D3D9PixelBuffer* currPixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[mip].get());
+					currPixelBuffer->bind(d3d9Device, volume, textureResources->pBaseTex);
+
+					volume->Release();
+				}
+				break;
+			};		
+		}		
+	}
+
+	PixelBufferPtr D3D9TextureCore::getBuffer(UINT32 face, UINT32 mipmap) 
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if(face >= mProperties.getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "A three dimensional cube has six faces");
+		if (mipmap > mProperties.getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Mipmap index out of range");
+
+		UINT32 idx = face*(mProperties.getNumMipmaps() + 1) + mipmap;
+
+		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
+		TextureResources* textureResources = getTextureResources(d3d9Device);
+		if (textureResources == nullptr || textureResources->pBaseTex == nullptr)
+		{				
+			createInternalResources(d3d9Device);
+			textureResources = getTextureResources(d3d9Device);			
+		}
+	
+		assert(textureResources != nullptr);
+		assert(idx < mSurfaceList.size());
+		return mSurfaceList[idx];
+	}
+
+	bool D3D9TextureCore::useDefaultPool()
+	{
+		int usage = mProperties.getUsage();
+		return (usage & TU_RENDERTARGET) || (usage & TU_DEPTHSTENCIL) || ((usage & TU_DYNAMIC) && mDynamicTextures);
+	}
+	
+	void D3D9TextureCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device) 
+	{		
+		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
+
+		if (D3D9RenderAPI::getResourceManager()->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES)
+			createInternalResources(d3d9Device);
+	}
+
+	void D3D9TextureCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device) 
+	{				
+		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
+
+		auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
+
+		if (iterFind != mMapDeviceToTextureResources.end())
+		{			
+			TextureResources* textureResource = iterFind->second;
+
+			for(unsigned int i = 0; i < mSurfaceList.size(); ++i)
+			{
+				D3D9PixelBuffer* pixelBuffer = static_cast<D3D9PixelBuffer*>(mSurfaceList[i].get());
+
+				pixelBuffer->destroyBufferResources(d3d9Device);			
+			}
+
+			freeTextureResources(d3d9Device, textureResource);
+
+			if(textureResource != nullptr)
+				bs_delete(textureResource);
+
+			mMapDeviceToTextureResources.erase(iterFind);
+		}	
+	}
+
+	void D3D9TextureCore::notifyOnDeviceLost(IDirect3DDevice9* d3d9Device) 
+	{		
+		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
+
+		if(mD3DPool == D3DPOOL_DEFAULT)
+		{
+			auto iterFind = mMapDeviceToTextureResources.find(d3d9Device);
+
+			if (iterFind != mMapDeviceToTextureResources.end())
+			{
+				TextureResources* textureResource = iterFind->second;				
+				freeTextureResources(d3d9Device, textureResource);
+			}					
+		}		
+	}
+
+	void D3D9TextureCore::notifyOnDeviceReset(IDirect3DDevice9* d3d9Device) 
+	{		
+		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
+
+		if(mD3DPool == D3DPOOL_DEFAULT)
+		{			
+			createInternalResources(d3d9Device);
+		}
+	}
+
+	IDirect3DBaseTexture9* D3D9TextureCore::getTexture_internal()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		TextureResources* textureResources;			
+		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
+			
+		textureResources = getTextureResources(d3d9Device);		
+		if (textureResources == nullptr || textureResources->pBaseTex == nullptr)
+		{			
+			createInternalResources(d3d9Device);
+			textureResources = getTextureResources(d3d9Device);			
+		}
+
+		assert(textureResources); 
+		assert(textureResources->pBaseTex); 
+
+		return textureResources->pBaseTex;
+	}
+
+	IDirect3DTexture9* D3D9TextureCore::getNormTexture_internal()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		TextureResources* textureResources;
+		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
+		
+		textureResources = getTextureResources(d3d9Device);		
+		if (textureResources == nullptr || textureResources->pNormTex == nullptr)
+		{
+			createInternalResources(d3d9Device);
+			textureResources = getTextureResources(d3d9Device);			
+		}
+		assert(textureResources); 
+		assert(textureResources->pNormTex); 
+
+		return textureResources->pNormTex;
+	}
+
+	IDirect3DCubeTexture9* D3D9TextureCore::getCubeTexture_internal()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		TextureResources* textureResources;
+		IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
+		
+		textureResources = getTextureResources(d3d9Device);		
+		if (textureResources == nullptr || textureResources->pCubeTex)
+		{
+			createInternalResources(d3d9Device);
+			textureResources = getTextureResources(d3d9Device);			
+		}
+
+		assert(textureResources); 
+		assert(textureResources->pCubeTex); 
+
+		return textureResources->pCubeTex;
+	}	
 }

+ 1 - 4
BansheeEditor/Source/BsDockManager.cpp

@@ -658,14 +658,11 @@ namespace BansheeEngine
 
 		std::function<void(DockContainer*)> undockWidgets = [&](DockContainer* container)
 		{
-			if (!container->mIsLeaf)
+			while (!container->mIsLeaf)
 			{
 				// Due to the way undocking works a container can be transfromed from non-leaf to leaf
 				// if its child container is deleted, so we need to check to that specially
 				undockWidgets(container->mChildren[0]);
-
-				if (!container->mIsLeaf)
-					undockWidgets(container->mChildren[1]);
 			}
 
 			if (container->mIsLeaf)

+ 284 - 284
BansheeGLRenderAPI/Source/BsGLTexture.cpp

@@ -1,285 +1,285 @@
-#include "BsGLTexture.h"
-#include "BsGLSupport.h"
-#include "BsGLPixelFormat.h"
-#include "BsGLPixelBuffer.h"
-#include "BsException.h"
-#include "BsBitwise.h"
-#include "BsCoreThread.h"
-#include "BsTextureManager.h"
-#include "BsGLRenderTexture.h"
-#include "BsRenderStats.h"
-
-namespace BansheeEngine 
-{
-	GLTextureCore::GLTextureCore(GLSupport& support, TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, 
-		UINT32 numMipmaps, PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initialData)
-		: TextureCore(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount, initialData),
-		mTextureID(0), mGLSupport(support), mGLFormat(0)
-    { }
-
-	GLTextureCore::~GLTextureCore()
-    { 
-		mSurfaceList.clear();
-		glDeleteTextures(1, &mTextureID);
-
-		clearBufferViews();
-
-		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
-	}
-
-	void GLTextureCore::initialize()
-	{
-		UINT32 width = mProperties.getWidth();
-		UINT32 height = mProperties.getHeight();
-		UINT32 depth = mProperties.getDepth();
-		TextureType texType = mProperties.getTextureType();
-		PixelFormat pixFormat = mProperties.getFormat();
-		int usage = mProperties.getUsage();
-		UINT32 numMips = mProperties.getNumMipmaps();
-
-		// Check requested number of mipmaps
-		UINT32 maxMips = PixelUtil::getMaxMipmaps(width, height, depth, mProperties.getFormat());
-		if (numMips > maxMips)
-			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: " + toString(maxMips));
-
-		if ((usage & TU_RENDERTARGET) != 0)
-		{
-			if (texType != TEX_TYPE_2D)
-				BS_EXCEPT(NotImplementedException, "Only 2D render targets are supported at the moment");
-		}
-
-		if ((usage & TU_DEPTHSTENCIL) != 0)
-		{
-			if (texType != TEX_TYPE_2D)
-				BS_EXCEPT(NotImplementedException, "Only 2D depth stencil targets are supported at the moment");
-
-			if (!PixelUtil::isDepth(pixFormat))
-				BS_EXCEPT(NotImplementedException, "Supplied format is not a depth stencil format. Format: " + toString(pixFormat));
-		}
-
-		// Generate texture handle
-		glGenTextures(1, &mTextureID);
-
-		// Set texture type
-		glBindTexture(getGLTextureTarget(), mTextureID);
-
-		// This needs to be set otherwise the texture doesn't get rendered
-		glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, numMips);
-
-		// Allocate internal buffer so that glTexSubImageXD can be used
-		mGLFormat = GLPixelUtil::getClosestGLInternalFormat(pixFormat, mProperties.isHardwareGammaEnabled());
-
-		if (PixelUtil::isCompressed(pixFormat))
-		{
-			if((usage & TU_RENDERTARGET) != 0)
-				BS_EXCEPT(InvalidParametersException, "Cannot use a compressed format for a render target.");
-
-			if ((usage & TU_DEPTHSTENCIL) != 0)
-				BS_EXCEPT(InvalidParametersException, "Cannot use a compressed format for a depth stencil target.");
-		}
-
-		UINT32 sampleCount = mProperties.getMultisampleCount();
-		if ((usage & TU_RENDERTARGET) != 0 && mProperties.getTextureType() == TEX_TYPE_2D && sampleCount > 1)
-		{
-			glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, mGLFormat, width, height, GL_FALSE);
-		}
-		else if ((usage & TU_DEPTHSTENCIL) != 0)
-		{
-			if (sampleCount > 1)
-			{
-				glTexImage2DMultisample(GL_TEXTURE_2D, sampleCount, mGLFormat,
-					width, height, GL_FALSE);
-			}
-			else
-			{
-				GLenum depthStencilFormat = GLPixelUtil::getDepthStencilTypeFromFormat(pixFormat);
-
-				glTexImage2D(GL_TEXTURE_2D, 0, mGLFormat,
-					width, height, 0, 
-					GL_DEPTH_STENCIL, depthStencilFormat, nullptr);
-			}
-		}
-		else
-		{
-			GLenum baseFormat = GLPixelUtil::getGLOriginFormat(pixFormat);
-			GLenum baseDataType = GLPixelUtil::getGLOriginDataType(pixFormat);
-
-			// Run through this process to pre-generate mipmap pyramid
-			for (UINT32 mip = 0; mip <= numMips; mip++)
-			{
-				switch (texType)
-				{
-				case TEX_TYPE_1D:
-					glTexImage1D(GL_TEXTURE_1D, mip, mGLFormat, width, 0,
-						baseFormat, baseDataType, nullptr);
-
-					break;
-				case TEX_TYPE_2D:
-					glTexImage2D(GL_TEXTURE_2D, mip, mGLFormat,
-						width, height, 0, baseFormat, baseDataType, nullptr);
-					break;
-				case TEX_TYPE_3D:
-					glTexImage3D(GL_TEXTURE_3D, mip, mGLFormat, width, height,
-						depth, 0, baseFormat, baseDataType, nullptr);
-					break;
-				case TEX_TYPE_CUBE_MAP:
-					for(UINT32 face = 0; face < 6; face++) 
-					{
-						glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, mGLFormat,
-							width, height, 0, baseFormat, baseDataType, nullptr);
-					}
-					break;
-				};
-
-				if(width > 1)
-					width = width/2;
-
-				if(height > 1)
-					height = height/2;
-
-				if(depth > 1)	
-					depth = depth/2;
-			}
-		}
-
-		createSurfaceList();
-
-		PixelBufferPtr buffer = getBuffer(0, 0);
-
-#if BS_DEBUG_MODE
-		if(buffer != nullptr)
-		{
-			if(pixFormat != buffer->getFormat())
-			{
-				BS_EXCEPT(InternalErrorException, "Could not create a texture buffer with wanted format: " + toString(pixFormat));
-			}
-		}
-#endif
-
-		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
-		TextureCore::initialize();
-	}
-
-    GLenum GLTextureCore::getGLTextureTarget() const
-    {
-		switch (mProperties.getTextureType())
-        {
-            case TEX_TYPE_1D:
-                return GL_TEXTURE_1D;
-            case TEX_TYPE_2D:
-				if (mProperties.getMultisampleCount() > 1)
-					return GL_TEXTURE_2D_MULTISAMPLE;
-				else
-					return GL_TEXTURE_2D;
-            case TEX_TYPE_3D:
-                return GL_TEXTURE_3D;
-            case TEX_TYPE_CUBE_MAP:
-                return GL_TEXTURE_CUBE_MAP;
-            default:
-                return 0;
-        };
-    }
-
-	GLuint GLTextureCore::getGLID() const
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		return mTextureID;
-	}
-
-	PixelData GLTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		if(mLockedBuffer != nullptr)
-			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
-
-		UINT32 mipWidth = mProperties.getWidth() >> mipLevel;
-		UINT32 mipHeight = mProperties.getHeight() >> mipLevel;
-		UINT32 mipDepth = mProperties.getDepth() >> mipLevel;
-
-		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
-
-		mLockedBuffer = getBuffer(face, mipLevel);
-		lockedArea.setExternalBuffer((UINT8*)mLockedBuffer->lock(options));
-
-		return lockedArea;
-	}
-
-	void GLTextureCore::unlockImpl()
-	{
-		if(mLockedBuffer == nullptr)
-			BS_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
-
-		mLockedBuffer->unlock();
-		mLockedBuffer = nullptr;
-	}
-
-
-	void GLTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		getBuffer(face, mipLevel)->download(dest);
-	}
-
-	void GLTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
-	{
-		if (mProperties.getMultisampleCount() > 1)
-			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
-
-		getBuffer(face, mipLevel)->upload(src, src.getExtents());
-	}
-
-	void GLTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
-	{
-		size_t numMips = std::min(mProperties.getNumMipmaps(), target->getProperties().getNumMipmaps());
-
-		GLTextureCore* destTex = static_cast<GLTextureCore*>(target.get());
-		GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());
-
-		destTex->getBuffer(destFace, destMipLevel)->blitFromTexture(src);
-	}
-
-	void GLTextureCore::createSurfaceList()
-	{
-		mSurfaceList.clear();
-		
-		for (UINT32 face = 0; face < mProperties.getNumFaces(); face++)
-		{
-			for (UINT32 mip = 0; mip <= mProperties.getNumMipmaps(); mip++)
-			{
-                GLPixelBuffer *buf = bs_new<GLTextureBuffer>(getGLTextureTarget(), mTextureID, face, mip,
-					static_cast<GpuBufferUsage>(mProperties.getUsage()), 
-					mProperties.isHardwareGammaEnabled(), mProperties.getMultisampleCount());
-
-				mSurfaceList.push_back(bs_shared_ptr<GLPixelBuffer>(buf));
-                if(buf->getWidth() == 0 || buf->getHeight() == 0 || buf->getDepth() == 0)
-                {
-					BS_EXCEPT(RenderingAPIException, 
-                        "Zero sized texture surface on texture face "
-						+ toString(face) 
-						+ " mipmap "+toString(mip)
-						+ ". Probably, the GL driver refused to create the texture.");
-                }
-			}
-		}
-	}
-	
-	std::shared_ptr<GLPixelBuffer> GLTextureCore::getBuffer(UINT32 face, UINT32 mipmap)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if(face >= mProperties.getNumFaces())
-			BS_EXCEPT(InvalidParametersException, "Face index out of range");
-
-		if (mipmap > mProperties.getNumMipmaps())
-			BS_EXCEPT(InvalidParametersException, "Mipmap index out of range");
-
-		unsigned int idx = face * (mProperties.getNumMipmaps() + 1) + mipmap;
-		assert(idx < mSurfaceList.size());
-		return mSurfaceList[idx];
-	}
+#include "BsGLTexture.h"
+#include "BsGLSupport.h"
+#include "BsGLPixelFormat.h"
+#include "BsGLPixelBuffer.h"
+#include "BsException.h"
+#include "BsBitwise.h"
+#include "BsCoreThread.h"
+#include "BsTextureManager.h"
+#include "BsGLRenderTexture.h"
+#include "BsRenderStats.h"
+
+namespace BansheeEngine 
+{
+	GLTextureCore::GLTextureCore(GLSupport& support, TextureType textureType, UINT32 width, UINT32 height, UINT32 depth, 
+		UINT32 numMipmaps, PixelFormat format, int usage, bool hwGamma, UINT32 multisampleCount, const PixelDataPtr& initialData)
+		: TextureCore(textureType, width, height, depth, numMipmaps, format, usage, hwGamma, multisampleCount, initialData),
+		mTextureID(0), mGLSupport(support), mGLFormat(0)
+    { }
+
+	GLTextureCore::~GLTextureCore()
+    { 
+		mSurfaceList.clear();
+		glDeleteTextures(1, &mTextureID);
+
+		clearBufferViews();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
+	}
+
+	void GLTextureCore::initialize()
+	{
+		UINT32 width = mProperties.getWidth();
+		UINT32 height = mProperties.getHeight();
+		UINT32 depth = mProperties.getDepth();
+		TextureType texType = mProperties.getTextureType();
+		PixelFormat pixFormat = mProperties.getFormat();
+		int usage = mProperties.getUsage();
+		UINT32 numMips = mProperties.getNumMipmaps();
+
+		// Check requested number of mipmaps
+		UINT32 maxMips = PixelUtil::getMaxMipmaps(width, height, depth, mProperties.getFormat());
+		if (numMips > maxMips)
+			BS_EXCEPT(InvalidParametersException, "Invalid number of mipmaps. Maximum allowed is: " + toString(maxMips));
+
+		if ((usage & TU_RENDERTARGET) != 0)
+		{
+			if (texType != TEX_TYPE_2D)
+				BS_EXCEPT(NotImplementedException, "Only 2D render targets are supported at the moment");
+		}
+
+		if ((usage & TU_DEPTHSTENCIL) != 0)
+		{
+			if (texType != TEX_TYPE_2D)
+				BS_EXCEPT(NotImplementedException, "Only 2D depth stencil targets are supported at the moment");
+
+			if (!PixelUtil::isDepth(pixFormat))
+				BS_EXCEPT(NotImplementedException, "Supplied format is not a depth stencil format. Format: " + toString(pixFormat));
+		}
+
+		// Generate texture handle
+		glGenTextures(1, &mTextureID);
+
+		// Set texture type
+		glBindTexture(getGLTextureTarget(), mTextureID);
+
+		// This needs to be set otherwise the texture doesn't get rendered
+		glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, numMips);
+
+		// Allocate internal buffer so that glTexSubImageXD can be used
+		mGLFormat = GLPixelUtil::getClosestGLInternalFormat(pixFormat, mProperties.isHardwareGammaEnabled());
+
+		if (PixelUtil::isCompressed(pixFormat))
+		{
+			if((usage & TU_RENDERTARGET) != 0)
+				BS_EXCEPT(InvalidParametersException, "Cannot use a compressed format for a render target.");
+
+			if ((usage & TU_DEPTHSTENCIL) != 0)
+				BS_EXCEPT(InvalidParametersException, "Cannot use a compressed format for a depth stencil target.");
+		}
+
+		UINT32 sampleCount = mProperties.getMultisampleCount();
+		if ((usage & TU_RENDERTARGET) != 0 && mProperties.getTextureType() == TEX_TYPE_2D && sampleCount > 1)
+		{
+			glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, mGLFormat, width, height, GL_FALSE);
+		}
+		else if ((usage & TU_DEPTHSTENCIL) != 0)
+		{
+			if (sampleCount > 1)
+			{
+				glTexImage2DMultisample(GL_TEXTURE_2D, sampleCount, mGLFormat,
+					width, height, GL_FALSE);
+			}
+			else
+			{
+				GLenum depthStencilFormat = GLPixelUtil::getDepthStencilTypeFromFormat(pixFormat);
+
+				glTexImage2D(GL_TEXTURE_2D, 0, mGLFormat,
+					width, height, 0, 
+					GL_DEPTH_STENCIL, depthStencilFormat, nullptr);
+			}
+		}
+		else
+		{
+			GLenum baseFormat = GLPixelUtil::getGLOriginFormat(pixFormat);
+			GLenum baseDataType = GLPixelUtil::getGLOriginDataType(pixFormat);
+
+			// Run through this process to pre-generate mipmap pyramid
+			for (UINT32 mip = 0; mip <= numMips; mip++)
+			{
+				switch (texType)
+				{
+				case TEX_TYPE_1D:
+					glTexImage1D(GL_TEXTURE_1D, mip, mGLFormat, width, 0,
+						baseFormat, baseDataType, nullptr);
+
+					break;
+				case TEX_TYPE_2D:
+					glTexImage2D(GL_TEXTURE_2D, mip, mGLFormat,
+						width, height, 0, baseFormat, baseDataType, nullptr);
+					break;
+				case TEX_TYPE_3D:
+					glTexImage3D(GL_TEXTURE_3D, mip, mGLFormat, width, height,
+						depth, 0, baseFormat, baseDataType, nullptr);
+					break;
+				case TEX_TYPE_CUBE_MAP:
+					for(UINT32 face = 0; face < 6; face++) 
+					{
+						glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, mGLFormat,
+							width, height, 0, baseFormat, baseDataType, nullptr);
+					}
+					break;
+				};
+
+				if(width > 1)
+					width = width/2;
+
+				if(height > 1)
+					height = height/2;
+
+				if(depth > 1)	
+					depth = depth/2;
+			}
+		}
+
+		createSurfaceList();
+
+		PixelBufferPtr buffer = getBuffer(0, 0);
+
+#if BS_DEBUG_MODE
+		if(buffer != nullptr)
+		{
+			if(pixFormat != buffer->getFormat())
+			{
+				BS_EXCEPT(InternalErrorException, "Could not create a texture buffer with wanted format: " + toString(pixFormat));
+			}
+		}
+#endif
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
+		TextureCore::initialize();
+	}
+
+    GLenum GLTextureCore::getGLTextureTarget() const
+    {
+		switch (mProperties.getTextureType())
+        {
+            case TEX_TYPE_1D:
+                return GL_TEXTURE_1D;
+            case TEX_TYPE_2D:
+				if (mProperties.getMultisampleCount() > 1)
+					return GL_TEXTURE_2D_MULTISAMPLE;
+				else
+					return GL_TEXTURE_2D;
+            case TEX_TYPE_3D:
+                return GL_TEXTURE_3D;
+            case TEX_TYPE_CUBE_MAP:
+                return GL_TEXTURE_CUBE_MAP;
+            default:
+                return 0;
+        };
+    }
+
+	GLuint GLTextureCore::getGLID() const
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		return mTextureID;
+	}
+
+	PixelData GLTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		if(mLockedBuffer != nullptr)
+			BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
+
+		UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
+		UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
+		UINT32 mipDepth = std::max(1u, mProperties.getDepth() >> mipLevel);
+
+		PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
+
+		mLockedBuffer = getBuffer(face, mipLevel);
+		lockedArea.setExternalBuffer((UINT8*)mLockedBuffer->lock(options));
+
+		return lockedArea;
+	}
+
+	void GLTextureCore::unlockImpl()
+	{
+		if(mLockedBuffer == nullptr)
+			BS_EXCEPT(InternalErrorException, "Trying to unlock a buffer that's not locked.");
+
+		mLockedBuffer->unlock();
+		mLockedBuffer = nullptr;
+	}
+
+
+	void GLTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		getBuffer(face, mipLevel)->download(dest);
+	}
+
+	void GLTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
+	{
+		if (mProperties.getMultisampleCount() > 1)
+			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
+
+		getBuffer(face, mipLevel)->upload(src, src.getExtents());
+	}
+
+	void GLTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
+	{
+		size_t numMips = std::min(mProperties.getNumMipmaps(), target->getProperties().getNumMipmaps());
+
+		GLTextureCore* destTex = static_cast<GLTextureCore*>(target.get());
+		GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());
+
+		destTex->getBuffer(destFace, destMipLevel)->blitFromTexture(src);
+	}
+
+	void GLTextureCore::createSurfaceList()
+	{
+		mSurfaceList.clear();
+		
+		for (UINT32 face = 0; face < mProperties.getNumFaces(); face++)
+		{
+			for (UINT32 mip = 0; mip <= mProperties.getNumMipmaps(); mip++)
+			{
+                GLPixelBuffer *buf = bs_new<GLTextureBuffer>(getGLTextureTarget(), mTextureID, face, mip,
+					static_cast<GpuBufferUsage>(mProperties.getUsage()), 
+					mProperties.isHardwareGammaEnabled(), mProperties.getMultisampleCount());
+
+				mSurfaceList.push_back(bs_shared_ptr<GLPixelBuffer>(buf));
+                if(buf->getWidth() == 0 || buf->getHeight() == 0 || buf->getDepth() == 0)
+                {
+					BS_EXCEPT(RenderingAPIException, 
+                        "Zero sized texture surface on texture face "
+						+ toString(face) 
+						+ " mipmap "+toString(mip)
+						+ ". Probably, the GL driver refused to create the texture.");
+                }
+			}
+		}
+	}
+	
+	std::shared_ptr<GLPixelBuffer> GLTextureCore::getBuffer(UINT32 face, UINT32 mipmap)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if(face >= mProperties.getNumFaces())
+			BS_EXCEPT(InvalidParametersException, "Face index out of range");
+
+		if (mipmap > mProperties.getNumMipmaps())
+			BS_EXCEPT(InvalidParametersException, "Mipmap index out of range");
+
+		unsigned int idx = face * (mProperties.getNumMipmaps() + 1) + mipmap;
+		assert(idx < mSurfaceList.size());
+		return mSurfaceList[idx];
+	}
 }

+ 1 - 4
MBansheeEditor/Inspectors/RenderableInspector.cs

@@ -62,10 +62,7 @@ namespace BansheeEditor
             }
 
             if (rebuildMaterialsGUI)
-            {
-                materials = renderable.Materials;
                 BuildMaterialsGUI();
-            }
 
             meshField.Value = renderable.Mesh;
 
@@ -124,7 +121,7 @@ namespace BansheeEditor
             layersValue = 0;
             materials = renderable.Materials;
             materialsField = GUIArrayField<Material, MaterialArrayRow>.Create(new LocEdString("Materials"), materials, Layout);
-            materialsField.OnChanged += x => renderable.Materials = x;
+            materialsField.OnChanged += x => { materials = x; };
 
             meshField.OnChanged += x =>
             {

+ 133 - 133
MBansheeEngine/NativeRenderable.cs

@@ -1,133 +1,133 @@
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native Renderable class.
-    /// <see cref="Renderable"/>
-    /// </summary>
-    internal class NativeRenderable : ScriptObject
-    {
-        internal Mesh Mesh
-        {
-            get
-            {
-                return mesh; 
-            }
-            set
-            {
-                mesh = value;
-
-                IntPtr meshPtr = IntPtr.Zero;
-                if (mesh != null)
-                    meshPtr = mesh.GetCachedPtr();
-
-                Internal_SetMesh(mCachedPtr, meshPtr); 
-                
-            }
-        }
-
-        internal Bounds GetBounds(SceneObject parent)
-        {
-            AABox box;
-            Sphere sphere;
-
-            Internal_GetBounds(mCachedPtr, parent.mCachedPtr, out box, out sphere);
-
-            return new Bounds(box, sphere);
-        }
-
-        internal UInt64 Layers
-        {
-            get { return Internal_GetLayers(mCachedPtr); }
-            set { Internal_SetLayers(mCachedPtr, value); }
-        }
-
-        private Material[] materials = new Material[1];
-        private Mesh mesh;
-        
-        public NativeRenderable(SceneObject sceneObject)
-        {
-            IntPtr sceneObjPtr = IntPtr.Zero;
-            if (sceneObject != null)
-                sceneObjPtr = sceneObject.GetCachedPtr();
-
-            Internal_Create(this, sceneObjPtr);
-        }
-
-        internal Material[] Materials
-        {
-            get
-            {
-                if (materials == null)
-                    return null;
-
-                Material[] copy = new Material[materials.Length];
-                Array.Copy(materials, copy, materials.Length);
-
-                return copy;
-            }
-            set
-            {
-                materials = new Material[value.Length];
-                Array.Copy(value, materials, value.Length);
-                
-                Internal_SetMaterials(mCachedPtr, value);
-            }
-        }
-
-        internal Material GetMaterial(int index = 0)
-        {
-            return materials[index];
-        }
-
-        internal void SetMaterial(Material material, int index = 0)
-        {
-            materials[index] = material;
-
-            IntPtr materialPtr = IntPtr.Zero;
-            if (material != null)
-                materialPtr = material.GetCachedPtr();
-
-            Internal_SetMaterial(mCachedPtr, materialPtr, index);
-        }
-
-        internal void UpdateTransform(SceneObject sceneObject)
-        {
-            Internal_UpdateTransform(mCachedPtr, sceneObject.mCachedPtr);
-        }
-        
-        internal void OnDestroy()
-        {
-            Internal_OnDestroy(mCachedPtr);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Create(NativeRenderable instance, IntPtr parentSO);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMesh(IntPtr thisPtr, IntPtr mesh);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetBounds(IntPtr thisPtr, IntPtr parentSO, out AABox box, out Sphere sphere);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern UInt64 Internal_GetLayers(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLayers(IntPtr thisPtr, UInt64 layers);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr material, int index);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMaterials(IntPtr thisPtr, Material[] materials);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_OnDestroy(IntPtr thisPtr);
-    }
-}
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native Renderable class.
+    /// <see cref="Renderable"/>
+    /// </summary>
+    internal class NativeRenderable : ScriptObject
+    {
+        internal Mesh Mesh
+        {
+            get
+            {
+                return mesh; 
+            }
+            set
+            {
+                mesh = value;
+
+                IntPtr meshPtr = IntPtr.Zero;
+                if (mesh != null)
+                    meshPtr = mesh.GetCachedPtr();
+
+                Internal_SetMesh(mCachedPtr, meshPtr); 
+                
+            }
+        }
+
+        internal Bounds GetBounds(SceneObject parent)
+        {
+            AABox box;
+            Sphere sphere;
+
+            Internal_GetBounds(mCachedPtr, parent.mCachedPtr, out box, out sphere);
+
+            return new Bounds(box, sphere);
+        }
+
+        internal UInt64 Layers
+        {
+            get { return Internal_GetLayers(mCachedPtr); }
+            set { Internal_SetLayers(mCachedPtr, value); }
+        }
+
+        private Material[] materials = new Material[1];
+        private Mesh mesh;
+        
+        public NativeRenderable(SceneObject sceneObject)
+        {
+            IntPtr sceneObjPtr = IntPtr.Zero;
+            if (sceneObject != null)
+                sceneObjPtr = sceneObject.GetCachedPtr();
+
+            Internal_Create(this, sceneObjPtr);
+        }
+
+        internal Material[] Materials
+        {
+            get
+            {
+                if (materials == null)
+                    return null;
+
+                Material[] copy = new Material[materials.Length];
+                Array.Copy(materials, copy, materials.Length);
+
+                return copy;
+            }
+            set
+            {
+                materials = new Material[value.Length];
+                Array.Copy(value, materials, value.Length);
+
+                Internal_SetMaterials(mCachedPtr, value);
+            }
+        }
+
+        internal Material GetMaterial(int index = 0)
+        {
+            return materials[index];
+        }
+
+        internal void SetMaterial(Material material, int index = 0)
+        {
+            materials[index] = material;
+
+            IntPtr materialPtr = IntPtr.Zero;
+            if (material != null)
+                materialPtr = material.GetCachedPtr();
+
+            Internal_SetMaterial(mCachedPtr, materialPtr, index);
+        }
+
+        internal void UpdateTransform(SceneObject sceneObject)
+        {
+            Internal_UpdateTransform(mCachedPtr, sceneObject.mCachedPtr);
+        }
+        
+        internal void OnDestroy()
+        {
+            Internal_OnDestroy(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Create(NativeRenderable instance, IntPtr parentSO);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMesh(IntPtr thisPtr, IntPtr mesh);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetBounds(IntPtr thisPtr, IntPtr parentSO, out AABox box, out Sphere sphere);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern UInt64 Internal_GetLayers(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayers(IntPtr thisPtr, UInt64 layers);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr material, int index);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterials(IntPtr thisPtr, Material[] materials);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_OnDestroy(IntPtr thisPtr);
+    }
+}

+ 1 - 4
MBansheeEngine/Renderable.cs

@@ -120,10 +120,7 @@ namespace BansheeEngine
             _native.Mesh = serializableData.mesh;
 
             if (serializableData.materials != null)
-            {
-                for (int i = 0; i < serializableData.materials.Length; i++)
-                    _native.SetMaterial(serializableData.materials[i], i);
-            }
+                _native.Materials = serializableData.materials;
 
             _native.Layers = serializableData.layers;
         }

+ 6 - 0
RenderBeast/Source/BsRenderBeast.cpp

@@ -113,6 +113,12 @@ namespace BansheeEngine
 		bs_delete(mPointLightMat);
 		bs_delete(mDirLightMat);
 
+		mPointLightInGeomDSState = nullptr;
+		mPointLightOutGeomDSState = nullptr;
+
+		mPointLightInGeomRState = nullptr;
+		mPointLightOutGeomRState = nullptr;
+
 		RendererUtility::shutDown();
 
 		assert(mSamplerOverrides.empty());