Add SwiftShader source to repo

Oct 6 code drop from Transgaming
Review URL: https://chromereviews.googleplex.com/3846015
diff --git a/src/OpenGL ES 2.0/libGLESv2/Device.cpp b/src/OpenGL ES 2.0/libGLESv2/Device.cpp
new file mode 100644
index 0000000..68e293f
--- /dev/null
+++ b/src/OpenGL ES 2.0/libGLESv2/Device.cpp
@@ -0,0 +1,1042 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2011 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "Device.hpp"
+
+#include "Image.hpp"
+#include "Texture.h"
+
+#include "Renderer/Renderer.hpp"
+#include "Renderer/Clipper.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Main/Config.hpp"
+#include "Main/FrameBuffer.hpp"
+#include "Common/Math.hpp"
+#include "Common/Configurator.hpp"
+#include "Common/Timer.hpp"
+#include "../common/debug.h"
+
+bool localShaderConstants = true;
+
+namespace gl
+{
+	using namespace sw;
+
+	Device::Device(Context *context) : Renderer(context), context(context)
+	{
+		depthStencil = 0;
+		renderTarget = 0;
+
+		setDepthBufferEnable(true);
+		setFillMode(Context::FILL_SOLID);
+		setShadingMode(Context::SHADING_GOURAUD);
+		setDepthWriteEnable(true);
+		setAlphaTestEnable(false);
+		setSourceBlendFactor(Context::BLEND_ONE);
+		setDestBlendFactor(Context::BLEND_ZERO);
+		setCullMode(Context::CULL_COUNTERCLOCKWISE);
+		setDepthCompare(Context::DEPTH_LESSEQUAL);
+		setAlphaReference(0);
+		setAlphaCompare(Context::ALPHA_ALWAYS);
+		setAlphaBlendEnable(false);
+		setFogEnable(false);
+		setSpecularEnable(false);
+		setFogColor(0);
+		setPixelFogMode(Context::FOG_NONE);
+		setFogStart(0.0f);
+		setFogEnd(1.0f);
+		setFogDensity(1.0f);
+		setRangeFogEnable(false);
+		setStencilEnable(false);
+		setStencilFailOperation(Context::OPERATION_KEEP);
+		setStencilZFailOperation(Context::OPERATION_KEEP);
+		setStencilPassOperation(Context::OPERATION_KEEP);
+		setStencilCompare(Context::STENCIL_ALWAYS);
+		setStencilReference(0);
+		setStencilMask(0xFFFFFFFF);
+		setStencilWriteMask(0xFFFFFFFF);
+		setVertexFogMode(Context::FOG_NONE);
+		setClipFlags(0);
+		setPointSize(1.0f);
+		setPointSizeMin(1.0f);
+		setPointSpriteEnable(false);
+		setPointSizeMax(64.0f);
+		setColorWriteMask(0, 0x0000000F);
+		setBlendOperation(Context::BLENDOP_ADD);
+		scissorEnable = false;
+		setSlopeDepthBias(0.0f);
+		setTwoSidedStencil(false);
+		setStencilFailOperationCCW(Context::OPERATION_KEEP);
+		setStencilZFailOperationCCW(Context::OPERATION_KEEP);
+		setStencilPassOperationCCW(Context::OPERATION_KEEP);
+		setStencilCompareCCW(Context::STENCIL_ALWAYS);
+		setColorWriteMask(1, 0x0000000F);
+		setColorWriteMask(2, 0x0000000F);
+		setColorWriteMask(3, 0x0000000F);
+		setBlendConstant(0xFFFFFFFF);
+		setWriteSRGB(false);
+		setDepthBias(0.0f);
+		setSeparateAlphaBlendEnable(false);
+		setSourceBlendFactorAlpha(Context::BLEND_ONE);
+		setDestBlendFactorAlpha(Context::BLEND_ZERO);
+		setBlendOperationAlpha(Context::BLENDOP_ADD);
+
+		for(int i = 0; i < 16; i++)
+		{
+			setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+			setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+			setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+			setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
+			setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
+			setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
+			setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
+		}
+
+		for(int i = 0; i < 4; i++)
+		{
+			setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+			setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+			setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+			setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
+			setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
+			setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
+			setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
+		}
+
+		for(int i = 0; i < 6; i++)
+		{
+			float plane[4] = {0, 0, 0, 0};
+
+			setClipPlane(i, plane);
+		}
+
+		pixelShader = 0;
+		vertexShader = 0;
+
+		pixelShaderDirty = true;
+		pixelShaderConstantsFDirty = 0;
+		vertexShaderDirty = true;
+		vertexShaderConstantsFDirty = 0;
+
+		for(int i = 0; i < 224; i++)
+		{
+			float zero[4] = {0, 0, 0, 0};
+
+			setPixelShaderConstantF(i, zero, 1);
+		}
+
+		for(int i = 0; i < 256; i++)
+		{
+			float zero[4] = {0, 0, 0, 0};
+
+			setVertexShaderConstantF(i, zero, 1);
+		}
+	}
+
+	Device::~Device()
+	{		
+		if(depthStencil)
+		{
+			depthStencil->unbind();
+			depthStencil = 0;
+		}
+		
+		if(renderTarget)
+		{
+			renderTarget->unbind();
+			renderTarget = 0;
+		}
+
+		delete context;
+	}
+
+	void Device::clearColor(unsigned int color, unsigned int rgbaMask)
+	{
+		TRACE("unsigned long color = 0x%0.8X", color);
+
+		int x = viewport.x;
+		int y = viewport.y;
+		int width = viewport.width;
+		int height = viewport.height;
+
+		// Clamp against scissor rectangle
+		if(scissorEnable)
+		{
+			if(x < scissorRect.left) x = scissorRect.left;
+			if(y < scissorRect.top) y = scissorRect.top;
+			if(width > scissorRect.right - scissorRect.left) width = scissorRect.right - scissorRect.left;
+			if(height > scissorRect.bottom - scissorRect.top) height = scissorRect.bottom - scissorRect.top;
+		}
+
+		if(renderTarget)
+		{
+			renderTarget->clearColorBuffer(color, rgbaMask, x, y, width, height);
+		}
+	}
+
+	void Device::clearDepth(float z)
+	{
+		TRACE("float z = %f", z);
+
+		if(z > 1) z = 1;
+		if(z < 0) z = 0;
+
+		int x = viewport.x;
+		int y = viewport.y;
+		int width = viewport.width;
+		int height = viewport.height;
+
+		// Clamp against scissor rectangle
+		if(scissorEnable)
+		{
+			if(x < scissorRect.left) x = scissorRect.left;
+			if(y < scissorRect.top) y = scissorRect.top;
+			if(width > scissorRect.right - scissorRect.left) width = scissorRect.right - scissorRect.left;
+			if(height > scissorRect.bottom - scissorRect.top) height = scissorRect.bottom - scissorRect.top;
+		}
+
+		if(depthStencil)
+		{
+			depthStencil->clearDepthBuffer(z, x, y, width, height);
+		}
+	}
+
+	void Device::clearStencil(unsigned int stencil, unsigned int mask)
+	{
+		TRACE("unsigned long stencil = %d", stencil);
+
+		int x = viewport.x;
+		int y = viewport.y;
+		int width = viewport.width;
+		int height = viewport.height;
+
+		// Clamp against scissor rectangle
+		if(scissorEnable)
+		{
+			if(x < scissorRect.left) x = scissorRect.left;
+			if(y < scissorRect.top) y = scissorRect.top;
+			if(width > scissorRect.right - scissorRect.left) width = scissorRect.right - scissorRect.left;
+			if(height > scissorRect.bottom - scissorRect.top) height = scissorRect.bottom - scissorRect.top;
+		}
+
+		if(depthStencil)
+		{
+			depthStencil->clearStencilBuffer(stencil, mask, x, y, width, height);
+		}
+	}
+
+	Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
+	{
+		TRACE("unsigned int width = %d, unsigned int height = %d, sw::Format format = %d, int multiSampleDepth = %d, bool discard = %d", width, height, format, multiSampleDepth, discard);
+
+		if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
+		{
+			ERR("Invalid parameters");
+			return 0;
+		}
+		
+		bool lockable = true;
+
+		switch(format)
+		{
+	//	case FORMAT_D15S1:
+		case FORMAT_D24S8:
+		case FORMAT_D24X8:
+	//	case FORMAT_D24X4S4:
+		case FORMAT_D24FS8:
+		case FORMAT_D32:
+		case FORMAT_D16:
+			lockable = false;
+			break;
+	//	case FORMAT_S8_LOCKABLE:
+	//	case FORMAT_D16_LOCKABLE:
+		case FORMAT_D32F_LOCKABLE:
+	//	case FORMAT_D32_LOCKABLE:
+		case FORMAT_DF24:
+		case FORMAT_DF16:
+			lockable = true;
+			break;
+		default:
+			UNREACHABLE();
+		}
+
+		Image *surface = new Image(0, width, height, format, GL_NONE, GL_NONE, multiSampleDepth, lockable, true);
+
+		if(!surface)
+		{
+			ERR("Out of memory");
+			return 0;
+		}
+
+		surface->addRef();
+
+		return surface;
+	}
+
+	Image *Device::createOffscreenPlainSurface(unsigned int width, unsigned int height, sw::Format format)
+	{
+		TRACE("unsigned int width = %d, unsigned int height = %d, sw::Format format = %d", width, height, format);
+		
+		Image *surface = new Image(0, width, height, format, GL_NONE, GL_NONE, 1, true, false);
+
+		if(!surface)
+		{
+			ERR("Out of memory");
+			return 0;
+		}
+
+		surface->addRef();
+
+		return surface;
+	}
+
+	Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
+	{
+		TRACE("unsigned int width = %d, unsigned int height = %d, sw::Format format = %d, int multiSampleDepth = %d, bool lockable = %d", width, height, format, multiSampleDepth, lockable);
+
+		if(height > OUTLINE_RESOLUTION)
+		{
+			ERR("Invalid parameters");
+			return 0;
+		}
+
+		Image *surface = new Image(0, width, height, format, GL_NONE, GL_NONE, multiSampleDepth, lockable != FALSE, true);
+
+		if(!surface)
+		{
+			ERR("Out of memory");
+			return 0;
+		}
+
+		surface->addRef();
+		
+		return surface;
+	}
+
+	void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)
+	{
+		TRACE("");
+
+		if(!bindResources() || !primitiveCount)
+		{
+			return;
+		}
+
+		Context::DrawType drawType;
+
+		if(indexSize == 4)
+		{
+			switch(type)
+			{
+			case DRAW_POINTLIST:     drawType = Context::DRAW_INDEXEDPOINTLIST32;     break;
+			case DRAW_LINELIST:      drawType = Context::DRAW_INDEXEDLINELIST32;      break;
+			case DRAW_LINESTRIP:     drawType = Context::DRAW_INDEXEDLINESTRIP32;     break;
+			case DRAW_LINELOOP:      drawType = Context::DRAW_INDEXEDLINELOOP32;      break;
+			case DRAW_TRIANGLELIST:  drawType = Context::DRAW_INDEXEDTRIANGLELIST32;  break;
+			case DRAW_TRIANGLESTRIP: drawType = Context::DRAW_INDEXEDTRIANGLESTRIP32; break;
+			case DRAW_TRIANGLEFAN:   drawType = Context::DRAW_INDEXEDTRIANGLEFAN32;	  break;
+			default: UNREACHABLE();
+			}
+		}
+		else if(indexSize == 2)
+		{
+			switch(type)
+			{
+			case DRAW_POINTLIST:     drawType = Context::DRAW_INDEXEDPOINTLIST16;     break;
+			case DRAW_LINELIST:      drawType = Context::DRAW_INDEXEDLINELIST16;      break;
+			case DRAW_LINESTRIP:     drawType = Context::DRAW_INDEXEDLINESTRIP16;     break;
+			case DRAW_LINELOOP:      drawType = Context::DRAW_INDEXEDLINELOOP16;      break;
+			case DRAW_TRIANGLELIST:  drawType = Context::DRAW_INDEXEDTRIANGLELIST16;  break;
+			case DRAW_TRIANGLESTRIP: drawType = Context::DRAW_INDEXEDTRIANGLESTRIP16; break;
+			case DRAW_TRIANGLEFAN:   drawType = Context::DRAW_INDEXEDTRIANGLEFAN16;   break;
+			default: UNREACHABLE();
+			}
+		}
+		else if(indexSize == 1)
+		{
+			switch(type)
+			{
+			case DRAW_POINTLIST:     drawType = Context::DRAW_INDEXEDPOINTLIST8;     break;
+			case DRAW_LINELIST:      drawType = Context::DRAW_INDEXEDLINELIST8;      break;
+			case DRAW_LINESTRIP:     drawType = Context::DRAW_INDEXEDLINESTRIP8;     break;
+			case DRAW_LINELOOP:      drawType = Context::DRAW_INDEXEDLINELOOP8;      break;
+			case DRAW_TRIANGLELIST:  drawType = Context::DRAW_INDEXEDTRIANGLELIST8;  break;
+			case DRAW_TRIANGLESTRIP: drawType = Context::DRAW_INDEXEDTRIANGLESTRIP8; break;
+			case DRAW_TRIANGLEFAN:   drawType = Context::DRAW_INDEXEDTRIANGLEFAN8;   break;
+			default: UNREACHABLE();
+			}
+		}
+		else UNREACHABLE();
+
+		draw(drawType, indexOffset, primitiveCount);
+	}
+
+	void Device::drawPrimitive(PrimitiveType primitiveType, unsigned int primitiveCount)
+	{
+		TRACE("");
+
+		if(!bindResources() || !primitiveCount)
+		{
+			return;
+		}
+
+		setIndexBuffer(0);
+		
+		Context::DrawType drawType;
+
+		switch(primitiveType)
+		{
+		case DRAW_POINTLIST:     drawType = Context::DRAW_POINTLIST;     break;
+		case DRAW_LINELIST:      drawType = Context::DRAW_LINELIST;      break;
+		case DRAW_LINESTRIP:     drawType = Context::DRAW_LINESTRIP;     break;
+		case DRAW_LINELOOP:      drawType = Context::DRAW_LINELOOP;      break;
+		case DRAW_TRIANGLELIST:  drawType = Context::DRAW_TRIANGLELIST;  break;
+		case DRAW_TRIANGLESTRIP: drawType = Context::DRAW_TRIANGLESTRIP; break;
+		case DRAW_TRIANGLEFAN:   drawType = Context::DRAW_TRIANGLEFAN;   break;
+		default: UNREACHABLE();
+		}
+
+		draw(drawType, 0, primitiveCount);
+	}
+
+	Image *Device::getDepthStencilSurface()
+	{
+		TRACE("void");
+
+		if(depthStencil)
+		{
+			depthStencil->addRef();
+		}
+
+		return depthStencil;
+	}
+
+	bool Device::getRenderTargetData(Image *renderTarget, Image *destSurface)
+	{
+		TRACE("Image *renderTarget = 0x%0.8p, Image *destSurface = 0x%0.8p", renderTarget, destSurface);
+
+		if(!renderTarget || !destSurface)
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+		
+		if(renderTarget->getWidth()  != destSurface->getWidth() ||
+		   renderTarget->getHeight() != destSurface->getHeight() ||
+		   renderTarget->getInternalFormat() != destSurface->getInternalFormat())
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+
+		static void (__cdecl *blitFunction)(void *dst, void *src);
+		static Routine *blitRoutine;
+		static BlitState blitState = {0};
+
+		BlitState update;
+		update.width = renderTarget->getInternalWidth();
+		update.height = renderTarget->getInternalHeight();
+		update.depth = 32;
+		update.stride = destSurface->getInternalPitchB();
+		update.HDR = false;
+		update.cursorHeight = 0;
+		update.cursorWidth = 0;
+		
+		if(memcmp(&blitState, &update, sizeof(BlitState)) != 0)
+		{
+			blitState = update;
+			delete blitRoutine;
+
+			blitRoutine = FrameBuffer::copyRoutine(blitState);
+			blitFunction = (void(__cdecl*)(void*, void*))blitRoutine->getEntry();
+		}
+
+		void *dst = destSurface->lockInternal(0, 0, 0, LOCK_WRITEONLY, PUBLIC);
+		void *src = renderTarget->lockInternal(0, 0, 0, LOCK_WRITEONLY, PUBLIC);
+
+		blitFunction(dst, src);
+
+		destSurface->unlockInternal();
+		renderTarget->unlockInternal();
+
+		return true;
+	}
+
+	void Device::setDepthStencilSurface(Image *depthStencil)
+	{
+		TRACE("Image *newDepthStencil = 0x%0.8p", depthStencil);
+
+		if(this->depthStencil == depthStencil)
+		{
+			return;
+		}
+
+		if(depthStencil)
+		{
+			depthStencil->bind();
+		}
+
+		if(this->depthStencil)
+		{
+			this->depthStencil->unbind();
+		}
+
+		this->depthStencil = depthStencil;
+
+		setDepthStencil(depthStencil);
+	}
+
+	void Device::setPixelShader(PixelShader *pixelShader)
+	{
+		TRACE("PixelShader *shader = 0x%0.8p", pixelShader);
+
+		this->pixelShader = pixelShader;
+		pixelShaderDirty = true;
+	}
+
+	void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+	{
+		TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count);
+
+		for(unsigned int i = 0; i < count && startRegister + i < 224; i++)
+		{
+			pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
+			pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
+			pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
+			pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
+		}
+
+		pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty);
+		pixelShaderDirty = true;   // Reload DEF constants
+	}
+
+	void Device::setScissorEnable(bool enable)
+	{
+		scissorEnable = enable;
+	}
+
+	void Device::setRenderTarget(Image *iRenderTarget)
+	{
+		TRACE("Image *newRenderTarget = 0x%0.8p", iRenderTarget);
+
+		Image *renderTarget = static_cast<Image*>(iRenderTarget);
+
+		if(renderTarget)
+		{
+			renderTarget->bind();
+		}
+
+		if(this->renderTarget)
+		{
+			this->renderTarget->unbind();
+		}
+
+		this->renderTarget = renderTarget;
+
+		if(renderTarget)
+		{
+			// Reset viewport to size of current render target
+			viewport.x = 0;
+			viewport.y = 0;
+			viewport.width = renderTarget->getWidth();
+			viewport.height = renderTarget->getHeight();
+			viewport.minZ = 0;
+			viewport.maxZ = 1;
+
+			// Reset scissor rectangle to size of current render target
+			scissorRect.left = 0;
+			scissorRect.top = 0;
+			scissorRect.right = renderTarget->getWidth();
+			scissorRect.bottom = renderTarget->getHeight();
+		}
+
+		Renderer::setRenderTarget(0, renderTarget);
+	}
+
+	void Device::setScissorRect(const sw::Rect &rect)
+	{
+		TRACE("const sw::Rect *rect = 0x%0.8p", rect);
+
+		scissorRect = rect;
+	}
+
+	void Device::setVertexShader(VertexShader *vertexShader)
+	{
+		TRACE("VertexShader *shader = 0x%0.8p", vertexShader);
+
+		this->vertexShader = vertexShader;
+		vertexShaderDirty = true;
+	}
+
+	void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+	{
+		TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count);
+
+		for(unsigned int i = 0; i < count && startRegister + i < 256; i++)
+		{
+			vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
+			vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
+			vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
+			vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
+		}
+			
+		vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty);
+		vertexShaderDirty = true;   // Reload DEF constants
+	}
+
+	void Device::setViewport(const Viewport &viewport)
+	{
+		TRACE("const Viewport *viewport = 0x%0.8p", viewport);
+
+		this->viewport = viewport;
+	}
+
+	bool Device::stretchRect(Image *sourceSurface, const sw::Rect *sourceRect, Image *destSurface, const sw::Rect *destRect, bool filter)
+	{
+		TRACE("Image *sourceSurface = 0x%0.8p, const sw::Rect *sourceRect = 0x%0.8p, Image *destSurface = 0x%0.8p, const sw::Rect *destRect = 0x%0.8p, bool filter = %d", sourceSurface, sourceRect, destSurface, destRect, filter);
+
+		if(!sourceSurface || !destSurface || !validRectangle(sourceRect, sourceSurface) || !validRectangle(destRect, destSurface))
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+		
+		Image *source = static_cast<Image*>(sourceSurface);
+		Image *dest = static_cast<Image*>(destSurface);
+
+		int sWidth = source->getExternalWidth();
+		int sHeight = source->getExternalHeight();
+		int dWidth = dest->getExternalWidth();
+		int dHeight = dest->getExternalHeight();
+
+		Rect sRect;
+		Rect dRect;
+
+		if(sourceRect)
+		{
+			sRect = *sourceRect;
+		}
+		else
+		{
+			sRect.top = 0;
+			sRect.left = 0;
+			sRect.bottom = sHeight;
+			sRect.right = sWidth;
+		}
+
+		if(destRect)
+		{
+			dRect = *destRect;
+		}
+		else
+		{
+			dRect.top = 0;
+			dRect.left = 0;
+			dRect.bottom = dHeight;
+			dRect.right = dWidth;
+		}
+
+		bool scaling = (sRect.right - sRect.left != dRect.right - dRect.left) || (sRect.bottom - sRect.top != dRect.bottom - dRect.top);
+		bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
+		bool depthStencil = Image::isDepth(source->getInternalFormat()) || Image::isStencil(source->getInternalFormat());
+		bool alpha0xFF = false;
+
+		if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
+		   (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
+		{
+			equalFormats = true;
+			alpha0xFF = true;
+		}
+
+		if(depthStencil)   // Copy entirely, internally   // FIXME: Check
+		{
+			if(source->hasDepth())
+			{
+				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);
+				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);
+
+				unsigned int width = source->getInternalWidth();
+				unsigned int height = source->getInternalHeight();
+				unsigned int pitch = source->getInternalPitchB();
+
+				for(unsigned int y = 0; y < height; y++)
+				{
+					memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes
+
+					sourceBuffer += pitch;
+					destBuffer += pitch;
+				}
+
+				source->unlockInternal();
+				dest->unlockInternal();
+			}
+
+			if(source->hasStencil())
+			{
+				sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
+				sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
+
+				unsigned int width = source->getInternalWidth();
+				unsigned int height = source->getInternalHeight();
+				unsigned int pitch = source->getStencilPitchB();
+
+				for(unsigned int y = 0; y < height; y++)
+				{
+					memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes
+
+					sourceBuffer += pitch;
+					destBuffer += pitch;
+				}
+
+				source->unlockStencil();
+				dest->unlockStencil();
+			}
+		}
+		else if(!scaling && equalFormats)
+		{
+			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.left, sRect.top, 0, LOCK_READONLY, PUBLIC);
+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.left, dRect.top, 0, LOCK_READWRITE, PUBLIC);
+			unsigned int sourcePitch = source->getInternalPitchB();
+			unsigned int destPitch = dest->getInternalPitchB();
+
+			unsigned int width = dRect.right - dRect.left;
+			unsigned int height = dRect.bottom - dRect.top;
+			unsigned int bytes = width * Image::bytes(source->getInternalFormat());
+
+			for(unsigned int y = 0; y < height; y++)
+			{
+				memcpy(destBytes, sourceBytes, bytes);
+
+				if(alpha0xFF)
+				{
+					for(unsigned int x = 0; x < width; x++)
+					{
+						destBytes[4 * x + 3] = 0xFF;
+					}
+				}
+				
+				sourceBytes += sourcePitch;
+				destBytes += destPitch;
+			}
+
+			source->unlockInternal();
+			dest->unlockInternal();
+		}
+		else
+		{
+			blit(source, sRect, dest, dRect, scaling && filter);
+		}
+
+		return true;
+	}
+
+	bool Device::updateSurface(Image *sourceSurface, const sw::Rect *sourceRect, Image *destinationSurface, const POINT *destPoint)
+	{
+		TRACE("Image *sourceSurface = 0x%0.8p, const sw::Rect *sourceRect = 0x%0.8p, Image *destinationSurface = 0x%0.8p, const POINT *destPoint = 0x%0.8p", sourceSurface, sourceRect, destinationSurface, destPoint);
+
+		if(!sourceSurface || !destinationSurface)
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+
+		Rect sRect;
+		Rect dRect;
+		
+		if(sourceRect)
+		{
+			sRect.left = sourceRect->left;
+			sRect.top = sourceRect->top;
+			sRect.right = sourceRect->right;
+			sRect.bottom = sourceRect->bottom;
+		}
+		else
+		{
+			sRect.left = 0;
+			sRect.top = 0;
+			sRect.right = sourceSurface->getWidth();
+			sRect.bottom = sourceSurface->getHeight();
+		}
+
+		if(destPoint)
+		{
+			dRect.left = destPoint->x;
+			dRect.top = destPoint->y;
+			dRect.right = destPoint->x + sRect.right - sRect.left;
+			dRect.bottom = destPoint->y + sRect.bottom - sRect.top;
+		}
+		else
+		{
+			dRect.left = 0;
+			dRect.top = 0;
+			dRect.right = sRect.right - sRect.left;
+			dRect.bottom = sRect.bottom - sRect.top;
+		}
+
+		if(!validRectangle(&sRect, sourceSurface) || !validRectangle(&dRect, destinationSurface))
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+
+		int sWidth = sRect.right - sRect.left;
+		int sHeight = sRect.bottom - sRect.top;
+
+		int dWidth = dRect.right - dRect.left;
+		int dHeight = dRect.bottom - dRect.top;
+
+		if(sourceSurface->getMultiSampleDepth() > 1 ||
+		   destinationSurface->getMultiSampleDepth() > 1 ||
+		   sourceSurface->getInternalFormat() != destinationSurface->getInternalFormat())
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+		
+		unsigned char *sourceBuffer = (unsigned char*)sourceSurface->lock(sRect.left, sRect.top, LOCK_READONLY);
+		unsigned char *destinationBuffer = (unsigned char*)destinationSurface->lock(dRect.left, dRect.top, LOCK_WRITEONLY);
+
+		unsigned int width;
+		unsigned int height;
+		unsigned int bytes;
+
+		switch(sourceSurface->getInternalFormat())
+		{
+		#if S3TC_SUPPORT
+		case FORMAT_DXT1:
+		case FORMAT_ATI1:
+			width = (dWidth + 3) / 4;
+			height = (dHeight + 3) / 4;
+			bytes = width * 8;   // 64 bit per 4x4 block
+			break;
+	//	case FORMAT_DXT2:
+		case FORMAT_DXT3:
+	//	case FORMAT_DXT4:
+		case FORMAT_DXT5:
+		case FORMAT_ATI2:
+			width = (dWidth + 3) / 4;
+			height = (dHeight + 3) / 4;
+			bytes = width * 16;   // 128 bit per 4x4 block
+			break;
+		#endif
+		default:
+			width = dWidth;
+			height = dHeight;
+			bytes = width * Image::bytes(sourceSurface->getInternalFormat());
+		}
+
+		int sourcePitch = sourceSurface->getPitch();
+		int destinationPitch = destinationSurface->getPitch();
+
+		#if S3TC_SUPPORT
+		if(sourceSurface->getInternalFormat() == FORMAT_ATI1 || sourceSurface->getInternalFormat() == FORMAT_ATI2)
+		{
+			// Make the pitch correspond to 4 rows
+			sourcePitch *= 4;
+			destinationPitch *= 4;
+		}
+		#endif
+
+		for(unsigned int y = 0; y < height; y++)
+		{
+			memcpy(destinationBuffer, sourceBuffer, bytes);
+			
+			sourceBuffer += sourcePitch;
+			destinationBuffer += destinationPitch;
+		}
+
+		sourceSurface->unlock();
+		destinationSurface->unlock();
+		
+		return true;
+	}
+
+	bool Device::bindResources()
+	{
+		if(!bindViewport())
+		{
+			return false;   // Zero-area target region
+		}
+
+		bindShaderConstants();
+
+		return true;
+	}
+
+	void Device::bindShaderConstants()
+	{
+		if(pixelShaderDirty)
+		{
+			if(pixelShader)
+			{
+				if(pixelShaderConstantsFDirty)
+				{
+					Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty);
+				}
+
+				Renderer::setPixelShader(pixelShader);   // Loads shader constants set with DEF
+				pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF;   // Shader DEF'ed constants are dirty
+			}
+			else
+			{
+				setPixelShader(0);
+			}
+
+			pixelShaderDirty = false;
+		}
+
+		if(vertexShaderDirty)
+		{
+			if(vertexShader)
+			{
+				if(vertexShaderConstantsFDirty)
+				{
+					Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty);
+				}
+		
+				Renderer::setVertexShader(vertexShader);   // Loads shader constants set with DEF
+				vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF;   // Shader DEF'ed constants are dirty
+			}
+			else
+			{
+				setVertexShader(0);
+			}
+
+			vertexShaderDirty = false;
+		}
+	}
+	
+	bool Device::bindViewport()
+	{
+		if(viewport.width <= 0 || viewport.height <= 0)
+		{
+			return false;
+		}
+
+		if(scissorEnable)
+		{
+			Rect scissor = scissorRect;
+
+			long viewportLeft = viewport.x;
+			long viewportRight = viewport.x + viewport.width;
+			long viewportTop = viewport.y;
+			long viewportBottom = viewport.y + viewport.height;
+
+			// Intersection of scissor rectangle and viewport
+			if(viewportLeft > scissor.left) scissor.left = viewportLeft;
+			if(viewportTop > scissor.top) scissor.top = viewportTop;
+			if(viewportRight < scissor.right) scissor.right = viewportRight;
+			if(viewportBottom < scissor.bottom) scissor.bottom = viewportBottom;
+
+			if(scissor.left == scissor.right ||
+			   scissor.top == scissor.bottom)
+			{
+				return false;
+			}
+
+			// Dimensions of scissor rectangle relative to viewport
+			float relativeLeft = (float)(scissor.left - viewportLeft) / viewport.width;
+			float relativeRight = (float)(scissor.right - viewportLeft) / viewport.width;
+			float relativeTop = (float)(scissor.top - viewportTop) / viewport.height;
+			float relativeBottom = (float)(scissor.bottom - viewportTop) / viewport.height;
+
+			// Transformation of clip space coordinates
+			float sX = 1.0f / (relativeRight - relativeLeft);   // Scale
+			float tX = sX * ((0.5f - relativeLeft) - (relativeRight - 0.5f));   // Translate
+			float sY = 1.0f / (relativeBottom - relativeTop);   // Scale
+			float tY = sY * ((0.5f - relativeTop) - (relativeBottom - 0.5f));   // Translate
+
+			// Set the new viewport
+			sw::Viewport view;
+
+			view.setLeft((float)scissor.left);
+			view.setTop((float)scissor.top);
+			view.setWidth((float)(scissor.right - scissor.left));
+			view.setHeight((float)(scissor.bottom - scissor.top));
+
+			view.setNear(viewport.minZ);
+			view.setFar(viewport.maxZ);
+
+			Renderer::setViewport(view);
+			setPostTransformEnable(true);
+			setPosScale(sX, sY);
+			setPosOffset(tX, -tY);
+		}
+		else
+		{
+			// Set viewport
+			sw::Viewport view;
+
+			view.setLeft((float)viewport.x);
+			view.setTop((float)viewport.y);
+			view.setWidth((float)viewport.width);
+			view.setHeight((float)viewport.height);
+
+			view.setNear(viewport.minZ);
+			view.setFar(viewport.maxZ);
+
+			Renderer::setViewport(view);
+			setPostTransformEnable(false);
+		}
+
+		return true;
+	}
+
+	bool Device::validRectangle(const sw::Rect *rect, Image *surface)
+	{
+		if(!rect)
+		{
+			return true;
+		}
+
+		if(rect->right <= rect->left || rect->bottom <= rect->top)
+		{
+			return false;
+		}
+
+		if(rect->left < 0 || rect->top < 0)
+		{
+			return false;
+		}
+
+		if(rect->right > (int)surface->getWidth() || rect->bottom > (int)surface->getHeight())
+		{
+			return false;
+		}
+
+		return true;
+	}
+
+	void Device::finish()
+	{
+		if(renderTarget)
+		{
+			renderTarget->lock(0, 0, sw::LOCK_READWRITE);
+			renderTarget->unlock();
+		}
+	}
+}
+
+extern "C"
+{
+	gl::Device *createDevice()
+	{
+		sw::Context *context = new sw::Context();
+
+		if(context)
+		{
+			return new gl::Device(context);
+		}
+
+		return 0;
+	}
+}
\ No newline at end of file