Apply the Apache 2.0 license.

Change-Id: I4a7aeefedcd2d891093520d5a10ebefadcddb5be
Reviewed-on: https://swiftshader-review.googlesource.com/5320
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 65f29fc..7a7f022 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -1,608 +1,611 @@
-// SwiftShader Software Renderer

-//

-// Copyright(c) 2005-2013 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 "common/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"

-

-namespace es1

-{

-	using namespace sw;

-

-	Device::Device(Context *context) : Renderer(context, OpenGL, true), context(context)

-	{

-		renderTarget = nullptr;

-		depthBuffer = nullptr;

-		stencilBuffer = nullptr;

-

-		setDepthBufferEnable(true);

-		setFillMode(FILL_SOLID);

-		setShadingMode(SHADING_GOURAUD);

-		setDepthWriteEnable(true);

-		setAlphaTestEnable(false);

-		setSourceBlendFactor(BLEND_ONE);

-		setDestBlendFactor(BLEND_ZERO);

-		setCullMode(CULL_COUNTERCLOCKWISE);

-		setDepthCompare(DEPTH_LESSEQUAL);

-		setAlphaReference(0.0f);

-		setAlphaCompare(ALPHA_ALWAYS);

-		setAlphaBlendEnable(false);

-		setFogEnable(false);

-		setSpecularEnable(true);

-		setLocalViewer(false);

-		setFogColor(0);

-		setPixelFogMode(FOG_NONE);

-		setFogStart(0.0f);

-		setFogEnd(1.0f);

-		setFogDensity(1.0f);

-		setRangeFogEnable(false);

-		setStencilEnable(false);

-		setStencilFailOperation(OPERATION_KEEP);

-		setStencilZFailOperation(OPERATION_KEEP);

-		setStencilPassOperation(OPERATION_KEEP);

-		setStencilCompare(STENCIL_ALWAYS);

-		setStencilReference(0);

-		setStencilMask(0xFFFFFFFF);

-		setStencilWriteMask(0xFFFFFFFF);

-		setVertexFogMode(FOG_NONE);

-		setClipFlags(0);

-		setPointSize(1.0f);

-		setPointSizeMin(0.125f);

-        setPointSizeMax(8192.0f);

-		setColorWriteMask(0, 0x0000000F);

-		setBlendOperation(BLENDOP_ADD);

-		scissorEnable = false;

-		setSlopeDepthBias(0.0f);

-		setTwoSidedStencil(false);

-		setStencilFailOperationCCW(OPERATION_KEEP);

-		setStencilZFailOperationCCW(OPERATION_KEEP);

-		setStencilPassOperationCCW(OPERATION_KEEP);

-		setStencilCompareCCW(STENCIL_ALWAYS);

-		setColorWriteMask(1, 0x0000000F);

-		setColorWriteMask(2, 0x0000000F);

-		setColorWriteMask(3, 0x0000000F);

-		setBlendConstant(0xFFFFFFFF);

-		setWriteSRGB(false);

-		setDepthBias(0.0f);

-		setSeparateAlphaBlendEnable(false);

-		setSourceBlendFactorAlpha(BLEND_ONE);

-		setDestBlendFactorAlpha(BLEND_ZERO);

-		setBlendOperationAlpha(BLENDOP_ADD);

-		setPointSpriteEnable(true);

-

-		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);

-		}

-	}

-

-	Device::~Device()

-	{

-		if(renderTarget)

-		{

-			renderTarget->release();

-			renderTarget = nullptr;

-		}

-

-		if(depthBuffer)

-		{

-			depthBuffer->release();

-			depthBuffer = nullptr;

-		}

-

-		if(stencilBuffer)

-		{

-			stencilBuffer->release();

-			stencilBuffer = nullptr;

-		}

-

-		delete context;

-	}

-

-	void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)

-	{

-		if(!renderTarget || !rgbaMask)

-		{

-			return;

-		}

-

-		float rgba[4];

-		rgba[0] = red;

-		rgba[1] = green;

-		rgba[2] = blue;

-		rgba[3] = alpha;

-

-		sw::SliceRect clearRect = renderTarget->getRect();

-

-		if(scissorEnable)

-		{

-			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);

-		}

-

-		clear(rgba, FORMAT_A32B32G32R32F, renderTarget, clearRect, rgbaMask);

-	}

-

-	void Device::clearDepth(float z)

-	{

-		if(!depthBuffer)

-		{

-			return;

-		}

-

-		z = clamp01(z);

-		sw::SliceRect clearRect = depthBuffer->getRect();

-

-		if(scissorEnable)

-		{

-			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);

-		}

-

-		depthBuffer->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());

-	}

-

-	void Device::clearStencil(unsigned int stencil, unsigned int mask)

-	{

-		if(!stencilBuffer)

-		{

-			return;

-		}

-

-		sw::SliceRect clearRect = stencilBuffer->getRect();

-

-		if(scissorEnable)

-		{

-			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);

-		}

-

-		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());

-	}

-

-	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)

-	{

-		if(height > OUTLINE_RESOLUTION)

-		{

-			ERR("Invalid parameters: %dx%d", width, height);

-			return nullptr;

-		}

-

-		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_DF24S8:

-		case FORMAT_DF16S8:

-			lockable = true;

-			break;

-		default:

-			UNREACHABLE(format);

-		}

-

-		egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);

-

-		if(!surface)

-		{

-			ERR("Out of memory");

-			return nullptr;

-		}

-

-		return surface;

-	}

-

-	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)

-	{

-		if(height > OUTLINE_RESOLUTION)

-		{

-			ERR("Invalid parameters: %dx%d", width, height);

-			return nullptr;

-		}

-

-		egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);

-

-		if(!surface)

-		{

-			ERR("Out of memory");

-			return nullptr;

-		}

-

-		return surface;

-	}

-

-	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)

-	{

-		if(!bindResources() || !primitiveCount)

-		{

-			return;

-		}

-

-		draw(type, indexOffset, primitiveCount);

-	}

-

-	void Device::drawPrimitive(sw::DrawType type, unsigned int primitiveCount)

-	{

-		if(!bindResources() || !primitiveCount)

-		{

-			return;

-		}

-

-		setIndexBuffer(nullptr);

-

-		draw(type, 0, primitiveCount);

-	}

-

-	void Device::setScissorEnable(bool enable)

-	{

-		scissorEnable = enable;

-	}

-

-	void Device::setRenderTarget(int index, egl::Image *renderTarget)

-	{

-		if(renderTarget)

-		{

-			renderTarget->addRef();

-		}

-

-		if(this->renderTarget)

-		{

-			this->renderTarget->release();

-		}

-

-		this->renderTarget = renderTarget;

-

-		Renderer::setRenderTarget(index, renderTarget);

-	}

-

-	void Device::setDepthBuffer(egl::Image *depthBuffer)

-	{

-		if(this->depthBuffer == depthBuffer)

-		{

-			return;

-		}

-

-		if(depthBuffer)

-		{

-			depthBuffer->addRef();

-		}

-

-		if(this->depthBuffer)

-		{

-			this->depthBuffer->release();

-		}

-

-		this->depthBuffer = depthBuffer;

-

-		Renderer::setDepthBuffer(depthBuffer);

-	}

-

-	void Device::setStencilBuffer(egl::Image *stencilBuffer)

-	{

-		if(this->stencilBuffer == stencilBuffer)

-		{

-			return;

-		}

-

-		if(stencilBuffer)

-		{

-			stencilBuffer->addRef();

-		}

-

-		if(this->stencilBuffer)

-		{

-			this->stencilBuffer->release();

-		}

-

-		this->stencilBuffer = stencilBuffer;

-

-		Renderer::setStencilBuffer(stencilBuffer);

-	}

-

-	void Device::setScissorRect(const sw::Rect &rect)

-	{

-		scissorRect = rect;

-	}

-

-	void Device::setViewport(const Viewport &viewport)

-	{

-		this->viewport = viewport;

-	}

-

-	bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, bool filter)

-	{

-		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

-		{

-			ERR("Invalid parameters");

-			return false;

-		}

-

-		int sWidth = source->getWidth();

-		int sHeight = source->getHeight();

-		int dWidth = dest->getWidth();

-		int dHeight = dest->getHeight();

-

-		SliceRect sRect;

-		SliceRect dRect;

-

-		if(sourceRect)

-		{

-			sRect = *sourceRect;

-		}

-		else

-		{

-			sRect.y0 = 0;

-			sRect.x0 = 0;

-			sRect.y1 = sHeight;

-			sRect.x1 = sWidth;

-		}

-

-		if(destRect)

-		{

-			dRect = *destRect;

-		}

-		else

-		{

-			dRect.y0 = 0;

-			dRect.x0 = 0;

-			dRect.y1 = dHeight;

-			dRect.x1 = dWidth;

-		}

-

-		bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);

-		bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();

-		bool depthStencil = egl::Image::isDepth(source->getInternalFormat()) || egl::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, sRect.slice, LOCK_READONLY, PUBLIC);

-				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, dRect.slice, LOCK_DISCARD, PUBLIC);

-

-				unsigned int width = source->getWidth();

-				unsigned int height = source->getHeight();

-				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->getWidth();

-				unsigned int height = source->getHeight();

-				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.x0, sRect.y0, sRect.slice, LOCK_READONLY, PUBLIC);

-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, LOCK_READWRITE, PUBLIC);

-			unsigned int sourcePitch = source->getInternalPitchB();

-			unsigned int destPitch = dest->getInternalPitchB();

-

-			unsigned int width = dRect.x1 - dRect.x0;

-			unsigned int height = dRect.y1 - dRect.y0;

-			unsigned int bytes = width * egl::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::bindResources()

-	{

-		if(!bindViewport())

-		{

-			return false;   // Zero-area target region

-		}

-

-		return true;

-	}

-

-	bool Device::bindViewport()

-	{

-		if(viewport.width <= 0 || viewport.height <= 0)

-		{

-			return false;

-		}

-

-		if(scissorEnable)

-		{

-			if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)

-			{

-				return false;

-			}

-

-			sw::Rect scissor;

-			scissor.x0 = scissorRect.x0;

-			scissor.x1 = scissorRect.x1;

-			scissor.y0 = scissorRect.y0;

-			scissor.y1 = scissorRect.y1;

-

-			setScissor(scissor);

-		}

-		else

-		{

-			sw::Rect scissor;

-			scissor.x0 = viewport.x0;

-			scissor.x1 = viewport.x0 + viewport.width;

-			scissor.y0 = viewport.y0;

-			scissor.y1 = viewport.y0 + viewport.height;

-

-			if(renderTarget)

-			{

-				scissor.x0 = max(scissor.x0, 0);

-				scissor.x1 = min(scissor.x1, renderTarget->getWidth());

-				scissor.y0 = max(scissor.y0, 0);

-				scissor.y1 = min(scissor.y1, renderTarget->getHeight());

-			}

-

-			if(depthBuffer)

-			{

-				scissor.x0 = max(scissor.x0, 0);

-				scissor.x1 = min(scissor.x1, depthBuffer->getWidth());

-				scissor.y0 = max(scissor.y0, 0);

-				scissor.y1 = min(scissor.y1, depthBuffer->getHeight());

-			}

-

-			if(stencilBuffer)

-			{

-				scissor.x0 = max(scissor.x0, 0);

-				scissor.x1 = min(scissor.x1, stencilBuffer->getWidth());

-				scissor.y0 = max(scissor.y0, 0);

-				scissor.y1 = min(scissor.y1, stencilBuffer->getHeight());

-			}

-

-			setScissor(scissor);

-		}

-

-		sw::Viewport view;

-		view.x0 = (float)viewport.x0;

-		view.y0 = (float)viewport.y0;

-		view.width = (float)viewport.width;

-		view.height = (float)viewport.height;

-		view.minZ = viewport.minZ;

-		view.maxZ = viewport.maxZ;

-

-		Renderer::setViewport(view);

-

-		return true;

-	}

-

-	bool Device::validRectangle(const sw::Rect *rect, sw::Surface *surface)

-	{

-		if(!rect)

-		{

-			return true;

-		}

-

-		if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)

-		{

-			return false;

-		}

-

-		if(rect->x0 < 0 || rect->y0 < 0)

-		{

-			return false;

-		}

-

-		if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())

-		{

-			return false;

-		}

-

-		return true;

-	}

-

-	void Device::finish()

-	{

-		synchronize();

-	}

-}

+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Device.hpp"
+
+#include "common/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"
+
+namespace es1
+{
+	using namespace sw;
+
+	Device::Device(Context *context) : Renderer(context, OpenGL, true), context(context)
+	{
+		renderTarget = nullptr;
+		depthBuffer = nullptr;
+		stencilBuffer = nullptr;
+
+		setDepthBufferEnable(true);
+		setFillMode(FILL_SOLID);
+		setShadingMode(SHADING_GOURAUD);
+		setDepthWriteEnable(true);
+		setAlphaTestEnable(false);
+		setSourceBlendFactor(BLEND_ONE);
+		setDestBlendFactor(BLEND_ZERO);
+		setCullMode(CULL_COUNTERCLOCKWISE);
+		setDepthCompare(DEPTH_LESSEQUAL);
+		setAlphaReference(0.0f);
+		setAlphaCompare(ALPHA_ALWAYS);
+		setAlphaBlendEnable(false);
+		setFogEnable(false);
+		setSpecularEnable(true);
+		setLocalViewer(false);
+		setFogColor(0);
+		setPixelFogMode(FOG_NONE);
+		setFogStart(0.0f);
+		setFogEnd(1.0f);
+		setFogDensity(1.0f);
+		setRangeFogEnable(false);
+		setStencilEnable(false);
+		setStencilFailOperation(OPERATION_KEEP);
+		setStencilZFailOperation(OPERATION_KEEP);
+		setStencilPassOperation(OPERATION_KEEP);
+		setStencilCompare(STENCIL_ALWAYS);
+		setStencilReference(0);
+		setStencilMask(0xFFFFFFFF);
+		setStencilWriteMask(0xFFFFFFFF);
+		setVertexFogMode(FOG_NONE);
+		setClipFlags(0);
+		setPointSize(1.0f);
+		setPointSizeMin(0.125f);
+        setPointSizeMax(8192.0f);
+		setColorWriteMask(0, 0x0000000F);
+		setBlendOperation(BLENDOP_ADD);
+		scissorEnable = false;
+		setSlopeDepthBias(0.0f);
+		setTwoSidedStencil(false);
+		setStencilFailOperationCCW(OPERATION_KEEP);
+		setStencilZFailOperationCCW(OPERATION_KEEP);
+		setStencilPassOperationCCW(OPERATION_KEEP);
+		setStencilCompareCCW(STENCIL_ALWAYS);
+		setColorWriteMask(1, 0x0000000F);
+		setColorWriteMask(2, 0x0000000F);
+		setColorWriteMask(3, 0x0000000F);
+		setBlendConstant(0xFFFFFFFF);
+		setWriteSRGB(false);
+		setDepthBias(0.0f);
+		setSeparateAlphaBlendEnable(false);
+		setSourceBlendFactorAlpha(BLEND_ONE);
+		setDestBlendFactorAlpha(BLEND_ZERO);
+		setBlendOperationAlpha(BLENDOP_ADD);
+		setPointSpriteEnable(true);
+
+		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);
+		}
+	}
+
+	Device::~Device()
+	{
+		if(renderTarget)
+		{
+			renderTarget->release();
+			renderTarget = nullptr;
+		}
+
+		if(depthBuffer)
+		{
+			depthBuffer->release();
+			depthBuffer = nullptr;
+		}
+
+		if(stencilBuffer)
+		{
+			stencilBuffer->release();
+			stencilBuffer = nullptr;
+		}
+
+		delete context;
+	}
+
+	void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)
+	{
+		if(!renderTarget || !rgbaMask)
+		{
+			return;
+		}
+
+		float rgba[4];
+		rgba[0] = red;
+		rgba[1] = green;
+		rgba[2] = blue;
+		rgba[3] = alpha;
+
+		sw::SliceRect clearRect = renderTarget->getRect();
+
+		if(scissorEnable)
+		{
+			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+		}
+
+		clear(rgba, FORMAT_A32B32G32R32F, renderTarget, clearRect, rgbaMask);
+	}
+
+	void Device::clearDepth(float z)
+	{
+		if(!depthBuffer)
+		{
+			return;
+		}
+
+		z = clamp01(z);
+		sw::SliceRect clearRect = depthBuffer->getRect();
+
+		if(scissorEnable)
+		{
+			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+		}
+
+		depthBuffer->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
+	}
+
+	void Device::clearStencil(unsigned int stencil, unsigned int mask)
+	{
+		if(!stencilBuffer)
+		{
+			return;
+		}
+
+		sw::SliceRect clearRect = stencilBuffer->getRect();
+
+		if(scissorEnable)
+		{
+			clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+		}
+
+		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
+	}
+
+	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
+	{
+		if(height > OUTLINE_RESOLUTION)
+		{
+			ERR("Invalid parameters: %dx%d", width, height);
+			return nullptr;
+		}
+
+		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_DF24S8:
+		case FORMAT_DF16S8:
+			lockable = true;
+			break;
+		default:
+			UNREACHABLE(format);
+		}
+
+		egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
+
+		if(!surface)
+		{
+			ERR("Out of memory");
+			return nullptr;
+		}
+
+		return surface;
+	}
+
+	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
+	{
+		if(height > OUTLINE_RESOLUTION)
+		{
+			ERR("Invalid parameters: %dx%d", width, height);
+			return nullptr;
+		}
+
+		egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
+
+		if(!surface)
+		{
+			ERR("Out of memory");
+			return nullptr;
+		}
+
+		return surface;
+	}
+
+	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
+	{
+		if(!bindResources() || !primitiveCount)
+		{
+			return;
+		}
+
+		draw(type, indexOffset, primitiveCount);
+	}
+
+	void Device::drawPrimitive(sw::DrawType type, unsigned int primitiveCount)
+	{
+		if(!bindResources() || !primitiveCount)
+		{
+			return;
+		}
+
+		setIndexBuffer(nullptr);
+
+		draw(type, 0, primitiveCount);
+	}
+
+	void Device::setScissorEnable(bool enable)
+	{
+		scissorEnable = enable;
+	}
+
+	void Device::setRenderTarget(int index, egl::Image *renderTarget)
+	{
+		if(renderTarget)
+		{
+			renderTarget->addRef();
+		}
+
+		if(this->renderTarget)
+		{
+			this->renderTarget->release();
+		}
+
+		this->renderTarget = renderTarget;
+
+		Renderer::setRenderTarget(index, renderTarget);
+	}
+
+	void Device::setDepthBuffer(egl::Image *depthBuffer)
+	{
+		if(this->depthBuffer == depthBuffer)
+		{
+			return;
+		}
+
+		if(depthBuffer)
+		{
+			depthBuffer->addRef();
+		}
+
+		if(this->depthBuffer)
+		{
+			this->depthBuffer->release();
+		}
+
+		this->depthBuffer = depthBuffer;
+
+		Renderer::setDepthBuffer(depthBuffer);
+	}
+
+	void Device::setStencilBuffer(egl::Image *stencilBuffer)
+	{
+		if(this->stencilBuffer == stencilBuffer)
+		{
+			return;
+		}
+
+		if(stencilBuffer)
+		{
+			stencilBuffer->addRef();
+		}
+
+		if(this->stencilBuffer)
+		{
+			this->stencilBuffer->release();
+		}
+
+		this->stencilBuffer = stencilBuffer;
+
+		Renderer::setStencilBuffer(stencilBuffer);
+	}
+
+	void Device::setScissorRect(const sw::Rect &rect)
+	{
+		scissorRect = rect;
+	}
+
+	void Device::setViewport(const Viewport &viewport)
+	{
+		this->viewport = viewport;
+	}
+
+	bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, bool filter)
+	{
+		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))
+		{
+			ERR("Invalid parameters");
+			return false;
+		}
+
+		int sWidth = source->getWidth();
+		int sHeight = source->getHeight();
+		int dWidth = dest->getWidth();
+		int dHeight = dest->getHeight();
+
+		SliceRect sRect;
+		SliceRect dRect;
+
+		if(sourceRect)
+		{
+			sRect = *sourceRect;
+		}
+		else
+		{
+			sRect.y0 = 0;
+			sRect.x0 = 0;
+			sRect.y1 = sHeight;
+			sRect.x1 = sWidth;
+		}
+
+		if(destRect)
+		{
+			dRect = *destRect;
+		}
+		else
+		{
+			dRect.y0 = 0;
+			dRect.x0 = 0;
+			dRect.y1 = dHeight;
+			dRect.x1 = dWidth;
+		}
+
+		bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
+		bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
+		bool depthStencil = egl::Image::isDepth(source->getInternalFormat()) || egl::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, sRect.slice, LOCK_READONLY, PUBLIC);
+				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, dRect.slice, LOCK_DISCARD, PUBLIC);
+
+				unsigned int width = source->getWidth();
+				unsigned int height = source->getHeight();
+				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->getWidth();
+				unsigned int height = source->getHeight();
+				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.x0, sRect.y0, sRect.slice, LOCK_READONLY, PUBLIC);
+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, LOCK_READWRITE, PUBLIC);
+			unsigned int sourcePitch = source->getInternalPitchB();
+			unsigned int destPitch = dest->getInternalPitchB();
+
+			unsigned int width = dRect.x1 - dRect.x0;
+			unsigned int height = dRect.y1 - dRect.y0;
+			unsigned int bytes = width * egl::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::bindResources()
+	{
+		if(!bindViewport())
+		{
+			return false;   // Zero-area target region
+		}
+
+		return true;
+	}
+
+	bool Device::bindViewport()
+	{
+		if(viewport.width <= 0 || viewport.height <= 0)
+		{
+			return false;
+		}
+
+		if(scissorEnable)
+		{
+			if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
+			{
+				return false;
+			}
+
+			sw::Rect scissor;
+			scissor.x0 = scissorRect.x0;
+			scissor.x1 = scissorRect.x1;
+			scissor.y0 = scissorRect.y0;
+			scissor.y1 = scissorRect.y1;
+
+			setScissor(scissor);
+		}
+		else
+		{
+			sw::Rect scissor;
+			scissor.x0 = viewport.x0;
+			scissor.x1 = viewport.x0 + viewport.width;
+			scissor.y0 = viewport.y0;
+			scissor.y1 = viewport.y0 + viewport.height;
+
+			if(renderTarget)
+			{
+				scissor.x0 = max(scissor.x0, 0);
+				scissor.x1 = min(scissor.x1, renderTarget->getWidth());
+				scissor.y0 = max(scissor.y0, 0);
+				scissor.y1 = min(scissor.y1, renderTarget->getHeight());
+			}
+
+			if(depthBuffer)
+			{
+				scissor.x0 = max(scissor.x0, 0);
+				scissor.x1 = min(scissor.x1, depthBuffer->getWidth());
+				scissor.y0 = max(scissor.y0, 0);
+				scissor.y1 = min(scissor.y1, depthBuffer->getHeight());
+			}
+
+			if(stencilBuffer)
+			{
+				scissor.x0 = max(scissor.x0, 0);
+				scissor.x1 = min(scissor.x1, stencilBuffer->getWidth());
+				scissor.y0 = max(scissor.y0, 0);
+				scissor.y1 = min(scissor.y1, stencilBuffer->getHeight());
+			}
+
+			setScissor(scissor);
+		}
+
+		sw::Viewport view;
+		view.x0 = (float)viewport.x0;
+		view.y0 = (float)viewport.y0;
+		view.width = (float)viewport.width;
+		view.height = (float)viewport.height;
+		view.minZ = viewport.minZ;
+		view.maxZ = viewport.maxZ;
+
+		Renderer::setViewport(view);
+
+		return true;
+	}
+
+	bool Device::validRectangle(const sw::Rect *rect, sw::Surface *surface)
+	{
+		if(!rect)
+		{
+			return true;
+		}
+
+		if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
+		{
+			return false;
+		}
+
+		if(rect->x0 < 0 || rect->y0 < 0)
+		{
+			return false;
+		}
+
+		if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
+		{
+			return false;
+		}
+
+		return true;
+	}
+
+	void Device::finish()
+	{
+		synchronize();
+	}
+}