Copy libGLESv2 to libGLES_CM.

BUG=18110152

Change-Id: Ibf9b8c47e2d7c145d844ac4e69d6a20a7342d5db
Reviewed-on: https://swiftshader-review.googlesource.com/1230
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/GLES2/libGLES_CM/Buffer.cpp b/src/GLES2/libGLES_CM/Buffer.cpp
new file mode 100644
index 0000000..fc535ac
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Buffer.cpp
@@ -0,0 +1,83 @@
+// 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.
+//
+
+// Buffer.cpp: Implements the Buffer class, representing storage of vertex and/or
+// index data. Implements GL buffer objects and related functionality.
+// [OpenGL ES 2.0.24] section 2.9 page 21.
+
+#include "Buffer.h"
+
+#include "main.h"
+#include "VertexDataManager.h"
+#include "IndexDataManager.h"
+
+namespace gl
+{
+
+Buffer::Buffer(GLuint id) : RefCountObject(id)
+{
+    mContents = 0;
+    mSize = 0;
+    mUsage = GL_DYNAMIC_DRAW;
+}
+
+Buffer::~Buffer()
+{
+    if(mContents)
+	{
+		mContents->destruct();
+	}
+}
+
+void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
+{
+	if(mContents)
+	{
+		mContents->destruct();
+		mContents = 0;
+	}
+
+	mSize = size;
+	mUsage = usage;
+
+	if(size > 0)
+	{
+		const int padding = 1024;   // For SIMD processing of vertices
+		mContents = new sw::Resource(size + padding);
+
+		if(!mContents)
+		{
+			return error(GL_OUT_OF_MEMORY);
+		}
+
+		if(data)
+		{
+			memcpy((void*)mContents->getBuffer(), data, size);
+		}
+	}
+}
+
+void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
+{
+	if(mContents)
+	{
+		char *buffer = (char*)mContents->lock(sw::PUBLIC);
+		memcpy(buffer + offset, data, size);
+		mContents->unlock();
+	}
+}
+
+sw::Resource *Buffer::getResource()
+{
+	return mContents;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Buffer.h b/src/GLES2/libGLES_CM/Buffer.h
new file mode 100644
index 0000000..91580e6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Buffer.h
@@ -0,0 +1,54 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// Buffer.h: Defines the Buffer class, representing storage of vertex and/or

+// index data. Implements GL buffer objects and related functionality.

+// [OpenGL ES 2.0.24] section 2.9 page 21.

+

+#ifndef LIBGLESV2_BUFFER_H_

+#define LIBGLESV2_BUFFER_H_

+

+#include "RefCountObject.h"

+#include "Common/Resource.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+#include <cstddef>

+#include <vector>

+

+namespace gl

+{

+class Buffer : public RefCountObject

+{

+  public:

+    explicit Buffer(GLuint id);

+

+    virtual ~Buffer();

+

+    void bufferData(const void *data, GLsizeiptr size, GLenum usage);

+    void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);

+

+	const void *data() { return mContents ? mContents->getBuffer() : 0; }

+    size_t size() const { return mSize; }

+    GLenum usage() const { return mUsage; }

+

+	sw::Resource *getResource();

+

+  private:

+    sw::Resource *mContents;

+    size_t mSize;

+    GLenum mUsage;

+};

+

+}

+

+#endif   // LIBGLESV2_BUFFER_H_

diff --git a/src/GLES2/libGLES_CM/Context.cpp b/src/GLES2/libGLES_CM/Context.cpp
new file mode 100644
index 0000000..2eba52e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Context.cpp
@@ -0,0 +1,3052 @@
+// 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.

+//

+

+// Context.cpp: Implements the gl::Context class, managing all GL state and performing

+// rendering operations. It is the GLES2 specific implementation of EGLContext.

+

+#include "Context.h"

+

+#include "main.h"

+#include "mathutil.h"

+#include "utilities.h"

+#include "ResourceManager.h"

+#include "Buffer.h"

+#include "Fence.h"

+#include "Framebuffer.h"

+#include "Program.h"

+#include "Query.h"

+#include "Renderbuffer.h"

+#include "Shader.h"

+#include "Texture.h"

+#include "VertexDataManager.h"

+#include "IndexDataManager.h"

+#include "libEGL/Display.h"

+#include "Common/Half.hpp"

+

+#undef near

+#undef far

+

+namespace gl

+{

+Context::Context(const egl::Config *config, const Context *shareContext) : mConfig(config)

+{

+    mFenceHandleAllocator.setBaseHandle(0);

+

+    setClearColor(0.0f, 0.0f, 0.0f, 0.0f);

+

+    mState.depthClearValue = 1.0f;

+    mState.stencilClearValue = 0;

+

+    mState.cullFace = false;

+    mState.cullMode = GL_BACK;

+    mState.frontFace = GL_CCW;

+    mState.depthTest = false;

+    mState.depthFunc = GL_LESS;

+    mState.blend = false;

+    mState.sourceBlendRGB = GL_ONE;

+    mState.sourceBlendAlpha = GL_ONE;

+    mState.destBlendRGB = GL_ZERO;

+    mState.destBlendAlpha = GL_ZERO;

+    mState.blendEquationRGB = GL_FUNC_ADD;

+    mState.blendEquationAlpha = GL_FUNC_ADD;

+    mState.blendColor.red = 0;

+    mState.blendColor.green = 0;

+    mState.blendColor.blue = 0;

+    mState.blendColor.alpha = 0;

+    mState.stencilTest = false;

+    mState.stencilFunc = GL_ALWAYS;

+    mState.stencilRef = 0;

+    mState.stencilMask = -1;

+    mState.stencilWritemask = -1;

+    mState.stencilBackFunc = GL_ALWAYS;

+    mState.stencilBackRef = 0;

+    mState.stencilBackMask = - 1;

+    mState.stencilBackWritemask = -1;

+    mState.stencilFail = GL_KEEP;

+    mState.stencilPassDepthFail = GL_KEEP;

+    mState.stencilPassDepthPass = GL_KEEP;

+    mState.stencilBackFail = GL_KEEP;

+    mState.stencilBackPassDepthFail = GL_KEEP;

+    mState.stencilBackPassDepthPass = GL_KEEP;

+    mState.polygonOffsetFill = false;

+    mState.polygonOffsetFactor = 0.0f;

+    mState.polygonOffsetUnits = 0.0f;

+    mState.sampleAlphaToCoverage = false;

+    mState.sampleCoverage = false;

+    mState.sampleCoverageValue = 1.0f;

+    mState.sampleCoverageInvert = false;

+    mState.scissorTest = false;

+    mState.dither = true;

+    mState.generateMipmapHint = GL_DONT_CARE;

+    mState.fragmentShaderDerivativeHint = GL_DONT_CARE;

+

+    mState.lineWidth = 1.0f;

+

+    mState.viewportX = 0;

+    mState.viewportY = 0;

+    mState.viewportWidth = config->mDisplayMode.width;

+    mState.viewportHeight = config->mDisplayMode.height;

+    mState.zNear = 0.0f;

+    mState.zFar = 1.0f;

+

+    mState.scissorX = 0;

+    mState.scissorY = 0;

+    mState.scissorWidth = config->mDisplayMode.width;

+    mState.scissorHeight = config->mDisplayMode.height;

+

+    mState.colorMaskRed = true;

+    mState.colorMaskGreen = true;

+    mState.colorMaskBlue = true;

+    mState.colorMaskAlpha = true;

+    mState.depthMask = true;

+

+    if(shareContext != NULL)

+    {

+        mResourceManager = shareContext->mResourceManager;

+        mResourceManager->addRef();

+    }

+    else

+    {

+        mResourceManager = new ResourceManager();

+    }

+

+    // [OpenGL ES 2.0.24] section 3.7 page 83:

+    // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional

+    // and cube map texture state vectors respectively associated with them.

+    // In order that access to these initial textures not be lost, they are treated as texture

+    // objects all of whose names are 0.

+

+    mTexture2DZero.set(new Texture2D(0));

+    mTextureCubeMapZero.set(new TextureCubeMap(0));

+    mTextureExternalZero.set(new TextureExternal(0));

+

+    mState.activeSampler = 0;

+    bindArrayBuffer(0);

+    bindElementArrayBuffer(0);

+    bindTextureCubeMap(0);

+    bindTexture2D(0);

+    bindReadFramebuffer(0);

+    bindDrawFramebuffer(0);

+    bindRenderbuffer(0);

+

+    mState.currentProgram = 0;

+

+    mState.packAlignment = 4;

+    mState.unpackAlignment = 4;

+

+    mVertexDataManager = NULL;

+    mIndexDataManager = NULL;

+

+    mInvalidEnum = false;

+    mInvalidValue = false;

+    mInvalidOperation = false;

+    mOutOfMemory = false;

+    mInvalidFramebufferOperation = false;

+

+    mHasBeenCurrent = false;

+

+    markAllStateDirty();

+}

+

+Context::~Context()

+{

+    if(mState.currentProgram != 0)

+    {

+        Program *programObject = mResourceManager->getProgram(mState.currentProgram);

+        if(programObject)

+        {

+            programObject->release();

+        }

+        mState.currentProgram = 0;

+    }

+

+    while(!mFramebufferMap.empty())

+    {

+        deleteFramebuffer(mFramebufferMap.begin()->first);

+    }

+

+    while(!mFenceMap.empty())

+    {

+        deleteFence(mFenceMap.begin()->first);

+    }

+

+	while(!mQueryMap.empty())

+    {

+        deleteQuery(mQueryMap.begin()->first);

+    }

+

+    for(int type = 0; type < TEXTURE_TYPE_COUNT; type++)

+    {

+        for(int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++)

+        {

+            mState.samplerTexture[type][sampler].set(NULL);

+        }

+    }

+

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+    {

+        mState.vertexAttribute[i].mBoundBuffer.set(NULL);

+    }

+

+	for(int i = 0; i < QUERY_TYPE_COUNT; i++)

+    {

+        mState.activeQuery[i].set(NULL);

+    }

+

+    mState.arrayBuffer.set(NULL);

+    mState.elementArrayBuffer.set(NULL);

+    mState.renderbuffer.set(NULL);

+

+    mTexture2DZero.set(NULL);

+    mTextureCubeMapZero.set(NULL);

+    mTextureExternalZero.set(NULL);

+

+    delete mVertexDataManager;

+    delete mIndexDataManager;

+

+    mResourceManager->release();

+}

+

+void Context::makeCurrent(egl::Display *display, egl::Surface *surface)

+{

+    Device *device = display->getDevice();

+

+    if(!mHasBeenCurrent)

+    {

+        mVertexDataManager = new VertexDataManager(this);

+        mIndexDataManager = new IndexDataManager();

+

+        mState.viewportX = 0;

+        mState.viewportY = 0;

+        mState.viewportWidth = surface->getWidth();

+        mState.viewportHeight = surface->getHeight();

+

+        mState.scissorX = 0;

+        mState.scissorY = 0;

+        mState.scissorWidth = surface->getWidth();

+        mState.scissorHeight = surface->getHeight();

+

+        mHasBeenCurrent = true;

+    }

+

+    // Wrap the existing resources into GL objects and assign them to the '0' names

+    Image *defaultRenderTarget = surface->getRenderTarget();

+    Image *depthStencil = surface->getDepthStencil();

+

+    Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);

+    DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil);

+    Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero);

+

+    setFramebufferZero(framebufferZero);

+

+    if(defaultRenderTarget)

+    {

+        defaultRenderTarget->release();

+    }

+

+    if(depthStencil)

+    {

+        depthStencil->release();

+    }

+    

+    markAllStateDirty();

+}

+

+// This function will set all of the state-related dirty flags, so that all state is set during next pre-draw.

+void Context::markAllStateDirty()

+{

+    mAppliedProgramSerial = 0;

+

+    mDepthStateDirty = true;

+    mMaskStateDirty = true;

+    mBlendStateDirty = true;

+    mStencilStateDirty = true;

+    mPolygonOffsetStateDirty = true;

+    mSampleStateDirty = true;

+    mDitherStateDirty = true;

+    mFrontFaceDirty = true;

+}

+

+void Context::setClearColor(float red, float green, float blue, float alpha)

+{

+    mState.colorClearValue.red = red;

+    mState.colorClearValue.green = green;

+    mState.colorClearValue.blue = blue;

+    mState.colorClearValue.alpha = alpha;

+}

+

+void Context::setClearDepth(float depth)

+{

+    mState.depthClearValue = depth;

+}

+

+void Context::setClearStencil(int stencil)

+{

+    mState.stencilClearValue = stencil;

+}

+

+void Context::setCullFace(bool enabled)

+{

+    mState.cullFace = enabled;

+}

+

+bool Context::isCullFaceEnabled() const

+{

+    return mState.cullFace;

+}

+

+void Context::setCullMode(GLenum mode)

+{

+   mState.cullMode = mode;

+}

+

+void Context::setFrontFace(GLenum front)

+{

+    if(mState.frontFace != front)

+    {

+        mState.frontFace = front;

+        mFrontFaceDirty = true;

+    }

+}

+

+void Context::setDepthTest(bool enabled)

+{

+    if(mState.depthTest != enabled)

+    {

+        mState.depthTest = enabled;

+        mDepthStateDirty = true;

+    }

+}

+

+bool Context::isDepthTestEnabled() const

+{

+    return mState.depthTest;

+}

+

+void Context::setDepthFunc(GLenum depthFunc)

+{

+    if(mState.depthFunc != depthFunc)

+    {

+        mState.depthFunc = depthFunc;

+        mDepthStateDirty = true;

+    }

+}

+

+void Context::setDepthRange(float zNear, float zFar)

+{

+    mState.zNear = zNear;

+    mState.zFar = zFar;

+}

+

+void Context::setBlend(bool enabled)

+{

+    if(mState.blend != enabled)

+    {

+        mState.blend = enabled;

+        mBlendStateDirty = true;

+    }

+}

+

+bool Context::isBlendEnabled() const

+{

+    return mState.blend;

+}

+

+void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha)

+{

+    if(mState.sourceBlendRGB != sourceRGB ||

+       mState.sourceBlendAlpha != sourceAlpha ||

+       mState.destBlendRGB != destRGB ||

+       mState.destBlendAlpha != destAlpha)

+    {

+        mState.sourceBlendRGB = sourceRGB;

+        mState.destBlendRGB = destRGB;

+        mState.sourceBlendAlpha = sourceAlpha;

+        mState.destBlendAlpha = destAlpha;

+        mBlendStateDirty = true;

+    }

+}

+

+void Context::setBlendColor(float red, float green, float blue, float alpha)

+{

+    if(mState.blendColor.red != red ||

+       mState.blendColor.green != green ||

+       mState.blendColor.blue != blue ||

+       mState.blendColor.alpha != alpha)

+    {

+        mState.blendColor.red = red;

+        mState.blendColor.green = green;

+        mState.blendColor.blue = blue;

+        mState.blendColor.alpha = alpha;

+        mBlendStateDirty = true;

+    }

+}

+

+void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)

+{

+    if(mState.blendEquationRGB != rgbEquation ||

+       mState.blendEquationAlpha != alphaEquation)

+    {

+        mState.blendEquationRGB = rgbEquation;

+        mState.blendEquationAlpha = alphaEquation;

+        mBlendStateDirty = true;

+    }

+}

+

+void Context::setStencilTest(bool enabled)

+{

+    if(mState.stencilTest != enabled)

+    {

+        mState.stencilTest = enabled;

+        mStencilStateDirty = true;

+    }

+}

+

+bool Context::isStencilTestEnabled() const

+{

+    return mState.stencilTest;

+}

+

+void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask)

+{

+    if(mState.stencilFunc != stencilFunc ||

+        mState.stencilRef != stencilRef ||

+        mState.stencilMask != stencilMask)

+    {

+        mState.stencilFunc = stencilFunc;

+        mState.stencilRef = (stencilRef > 0) ? stencilRef : 0;

+        mState.stencilMask = stencilMask;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask)

+{

+    if(mState.stencilBackFunc != stencilBackFunc ||

+        mState.stencilBackRef != stencilBackRef ||

+        mState.stencilBackMask != stencilBackMask)

+    {

+        mState.stencilBackFunc = stencilBackFunc;

+        mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0;

+        mState.stencilBackMask = stencilBackMask;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setStencilWritemask(GLuint stencilWritemask)

+{

+    if(mState.stencilWritemask != stencilWritemask)

+    {

+        mState.stencilWritemask = stencilWritemask;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setStencilBackWritemask(GLuint stencilBackWritemask)

+{

+    if(mState.stencilBackWritemask != stencilBackWritemask)

+    {

+        mState.stencilBackWritemask = stencilBackWritemask;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass)

+{

+    if(mState.stencilFail != stencilFail ||

+        mState.stencilPassDepthFail != stencilPassDepthFail ||

+        mState.stencilPassDepthPass != stencilPassDepthPass)

+    {

+        mState.stencilFail = stencilFail;

+        mState.stencilPassDepthFail = stencilPassDepthFail;

+        mState.stencilPassDepthPass = stencilPassDepthPass;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass)

+{

+    if(mState.stencilBackFail != stencilBackFail ||

+        mState.stencilBackPassDepthFail != stencilBackPassDepthFail ||

+        mState.stencilBackPassDepthPass != stencilBackPassDepthPass)

+    {

+        mState.stencilBackFail = stencilBackFail;

+        mState.stencilBackPassDepthFail = stencilBackPassDepthFail;

+        mState.stencilBackPassDepthPass = stencilBackPassDepthPass;

+        mStencilStateDirty = true;

+    }

+}

+

+void Context::setPolygonOffsetFill(bool enabled)

+{

+    if(mState.polygonOffsetFill != enabled)

+    {

+        mState.polygonOffsetFill = enabled;

+        mPolygonOffsetStateDirty = true;

+    }

+}

+

+bool Context::isPolygonOffsetFillEnabled() const

+{

+    return mState.polygonOffsetFill;

+}

+

+void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units)

+{

+    if(mState.polygonOffsetFactor != factor ||

+        mState.polygonOffsetUnits != units)

+    {

+        mState.polygonOffsetFactor = factor;

+        mState.polygonOffsetUnits = units;

+        mPolygonOffsetStateDirty = true;

+    }

+}

+

+void Context::setSampleAlphaToCoverage(bool enabled)

+{

+    if(mState.sampleAlphaToCoverage != enabled)

+    {

+        mState.sampleAlphaToCoverage = enabled;

+        mSampleStateDirty = true;

+    }

+}

+

+bool Context::isSampleAlphaToCoverageEnabled() const

+{

+    return mState.sampleAlphaToCoverage;

+}

+

+void Context::setSampleCoverage(bool enabled)

+{

+    if(mState.sampleCoverage != enabled)

+    {

+        mState.sampleCoverage = enabled;

+        mSampleStateDirty = true;

+    }

+}

+

+bool Context::isSampleCoverageEnabled() const

+{

+    return mState.sampleCoverage;

+}

+

+void Context::setSampleCoverageParams(GLclampf value, bool invert)

+{

+    if(mState.sampleCoverageValue != value ||

+        mState.sampleCoverageInvert != invert)

+    {

+        mState.sampleCoverageValue = value;

+        mState.sampleCoverageInvert = invert;

+        mSampleStateDirty = true;

+    }

+}

+

+void Context::setScissorTest(bool enabled)

+{

+    mState.scissorTest = enabled;

+}

+

+bool Context::isScissorTestEnabled() const

+{

+    return mState.scissorTest;

+}

+

+void Context::setDither(bool enabled)

+{

+    if(mState.dither != enabled)

+    {

+        mState.dither = enabled;

+        mDitherStateDirty = true;

+    }

+}

+

+bool Context::isDitherEnabled() const

+{

+    return mState.dither;

+}

+

+void Context::setLineWidth(GLfloat width)

+{

+    mState.lineWidth = width;

+}

+

+void Context::setGenerateMipmapHint(GLenum hint)

+{

+    mState.generateMipmapHint = hint;

+}

+

+void Context::setFragmentShaderDerivativeHint(GLenum hint)

+{

+    mState.fragmentShaderDerivativeHint = hint;

+    // TODO: Propagate the hint to shader translator so we can write

+    // ddx, ddx_coarse, or ddx_fine depending on the hint.

+    // Ignore for now. It is valid for implementations to ignore hint.

+}

+

+void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height)

+{

+    mState.viewportX = x;

+    mState.viewportY = y;

+    mState.viewportWidth = width;

+    mState.viewportHeight = height;

+}

+

+void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)

+{

+    mState.scissorX = x;

+    mState.scissorY = y;

+    mState.scissorWidth = width;

+    mState.scissorHeight = height;

+}

+

+void Context::setColorMask(bool red, bool green, bool blue, bool alpha)

+{

+    if(mState.colorMaskRed != red || mState.colorMaskGreen != green ||

+       mState.colorMaskBlue != blue || mState.colorMaskAlpha != alpha)

+    {

+        mState.colorMaskRed = red;

+        mState.colorMaskGreen = green;

+        mState.colorMaskBlue = blue;

+        mState.colorMaskAlpha = alpha;

+        mMaskStateDirty = true;

+    }

+}

+

+void Context::setDepthMask(bool mask)

+{

+    if(mState.depthMask != mask)

+    {

+        mState.depthMask = mask;

+        mMaskStateDirty = true;

+    }

+}

+

+void Context::setActiveSampler(unsigned int active)

+{

+    mState.activeSampler = active;

+}

+

+GLuint Context::getReadFramebufferHandle() const

+{

+    return mState.readFramebuffer;

+}

+

+GLuint Context::getDrawFramebufferHandle() const

+{

+    return mState.drawFramebuffer;

+}

+

+GLuint Context::getRenderbufferHandle() const

+{

+    return mState.renderbuffer.id();

+}

+

+GLuint Context::getArrayBufferHandle() const

+{

+    return mState.arrayBuffer.id();

+}

+

+GLuint Context::getActiveQuery(GLenum target) const

+{

+    Query *queryObject = NULL;

+    

+    switch(target)

+    {

+    case GL_ANY_SAMPLES_PASSED_EXT:

+        queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get();

+        break;

+    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:

+        queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get();

+        break;

+    default:

+        ASSERT(false);

+    }

+

+    if(queryObject)

+    {

+        return queryObject->id();

+    }

+    

+	return 0;

+}

+

+void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)

+{

+    mState.vertexAttribute[attribNum].mArrayEnabled = enabled;

+}

+

+const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum)

+{

+    return mState.vertexAttribute[attribNum];

+}

+

+void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,

+                                   GLsizei stride, const void *pointer)

+{

+    mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer);

+    mState.vertexAttribute[attribNum].mSize = size;

+    mState.vertexAttribute[attribNum].mType = type;

+    mState.vertexAttribute[attribNum].mNormalized = normalized;

+    mState.vertexAttribute[attribNum].mStride = stride;

+    mState.vertexAttribute[attribNum].mPointer = pointer;

+}

+

+const void *Context::getVertexAttribPointer(unsigned int attribNum) const

+{

+    return mState.vertexAttribute[attribNum].mPointer;

+}

+

+const VertexAttributeArray &Context::getVertexAttributes()

+{

+    return mState.vertexAttribute;

+}

+

+void Context::setPackAlignment(GLint alignment)

+{

+    mState.packAlignment = alignment;

+}

+

+GLint Context::getPackAlignment() const

+{

+    return mState.packAlignment;

+}

+

+void Context::setUnpackAlignment(GLint alignment)

+{

+    mState.unpackAlignment = alignment;

+}

+

+GLint Context::getUnpackAlignment() const

+{

+    return mState.unpackAlignment;

+}

+

+GLuint Context::createBuffer()

+{

+    return mResourceManager->createBuffer();

+}

+

+GLuint Context::createProgram()

+{

+    return mResourceManager->createProgram();

+}

+

+GLuint Context::createShader(GLenum type)

+{

+    return mResourceManager->createShader(type);

+}

+

+GLuint Context::createTexture()

+{

+    return mResourceManager->createTexture();

+}

+

+GLuint Context::createRenderbuffer()

+{

+    return mResourceManager->createRenderbuffer();

+}

+

+// Returns an unused framebuffer name

+GLuint Context::createFramebuffer()

+{

+    GLuint handle = mFramebufferHandleAllocator.allocate();

+

+    mFramebufferMap[handle] = NULL;

+

+    return handle;

+}

+

+GLuint Context::createFence()

+{

+    GLuint handle = mFenceHandleAllocator.allocate();

+

+    mFenceMap[handle] = new Fence;

+

+    return handle;

+}

+

+// Returns an unused query name

+GLuint Context::createQuery()

+{

+    GLuint handle = mQueryHandleAllocator.allocate();

+

+    mQueryMap[handle] = NULL;

+

+    return handle;

+}

+

+void Context::deleteBuffer(GLuint buffer)

+{

+    if(mResourceManager->getBuffer(buffer))

+    {

+        detachBuffer(buffer);

+    }

+    

+    mResourceManager->deleteBuffer(buffer);

+}

+

+void Context::deleteShader(GLuint shader)

+{

+    mResourceManager->deleteShader(shader);

+}

+

+void Context::deleteProgram(GLuint program)

+{

+    mResourceManager->deleteProgram(program);

+}

+

+void Context::deleteTexture(GLuint texture)

+{

+    if(mResourceManager->getTexture(texture))

+    {

+        detachTexture(texture);

+    }

+

+    mResourceManager->deleteTexture(texture);

+}

+

+void Context::deleteRenderbuffer(GLuint renderbuffer)

+{

+    if(mResourceManager->getRenderbuffer(renderbuffer))

+    {

+        detachRenderbuffer(renderbuffer);

+    }

+    

+    mResourceManager->deleteRenderbuffer(renderbuffer);

+}

+

+void Context::deleteFramebuffer(GLuint framebuffer)

+{

+    FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer);

+

+    if(framebufferObject != mFramebufferMap.end())

+    {

+        detachFramebuffer(framebuffer);

+

+        mFramebufferHandleAllocator.release(framebufferObject->first);

+        delete framebufferObject->second;

+        mFramebufferMap.erase(framebufferObject);

+    }

+}

+

+void Context::deleteFence(GLuint fence)

+{

+    FenceMap::iterator fenceObject = mFenceMap.find(fence);

+

+    if(fenceObject != mFenceMap.end())

+    {

+        mFenceHandleAllocator.release(fenceObject->first);

+        delete fenceObject->second;

+        mFenceMap.erase(fenceObject);

+    }

+}

+

+void Context::deleteQuery(GLuint query)

+{

+    QueryMap::iterator queryObject = mQueryMap.find(query);

+    

+	if(queryObject != mQueryMap.end())

+    {

+        mQueryHandleAllocator.release(queryObject->first);

+        

+		if(queryObject->second)

+        {

+            queryObject->second->release();

+        }

+        

+		mQueryMap.erase(queryObject);

+    }

+}

+

+Buffer *Context::getBuffer(GLuint handle)

+{

+    return mResourceManager->getBuffer(handle);

+}

+

+Shader *Context::getShader(GLuint handle)

+{

+    return mResourceManager->getShader(handle);

+}

+

+Program *Context::getProgram(GLuint handle)

+{

+    return mResourceManager->getProgram(handle);

+}

+

+Texture *Context::getTexture(GLuint handle)

+{

+    return mResourceManager->getTexture(handle);

+}

+

+Renderbuffer *Context::getRenderbuffer(GLuint handle)

+{

+    return mResourceManager->getRenderbuffer(handle);

+}

+

+Framebuffer *Context::getReadFramebuffer()

+{

+    return getFramebuffer(mState.readFramebuffer);

+}

+

+Framebuffer *Context::getDrawFramebuffer()

+{

+    return getFramebuffer(mState.drawFramebuffer);

+}

+

+void Context::bindArrayBuffer(unsigned int buffer)

+{

+    mResourceManager->checkBufferAllocation(buffer);

+

+    mState.arrayBuffer.set(getBuffer(buffer));

+}

+

+void Context::bindElementArrayBuffer(unsigned int buffer)

+{

+    mResourceManager->checkBufferAllocation(buffer);

+

+    mState.elementArrayBuffer.set(getBuffer(buffer));

+}

+

+void Context::bindTexture2D(GLuint texture)

+{

+    mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);

+

+    mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture));

+}

+

+void Context::bindTextureCubeMap(GLuint texture)

+{

+    mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE);

+

+    mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture));

+}

+

+void Context::bindTextureExternal(GLuint texture)

+{

+    mResourceManager->checkTextureAllocation(texture, TEXTURE_EXTERNAL);

+

+    mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].set(getTexture(texture));

+}

+

+void Context::bindReadFramebuffer(GLuint framebuffer)

+{

+    if(!getFramebuffer(framebuffer))

+    {

+        mFramebufferMap[framebuffer] = new Framebuffer();

+    }

+

+    mState.readFramebuffer = framebuffer;

+}

+

+void Context::bindDrawFramebuffer(GLuint framebuffer)

+{

+    if(!getFramebuffer(framebuffer))

+    {

+        mFramebufferMap[framebuffer] = new Framebuffer();

+    }

+

+    mState.drawFramebuffer = framebuffer;

+}

+

+void Context::bindRenderbuffer(GLuint renderbuffer)

+{

+    mResourceManager->checkRenderbufferAllocation(renderbuffer);

+

+    mState.renderbuffer.set(getRenderbuffer(renderbuffer));

+}

+

+void Context::useProgram(GLuint program)

+{

+    GLuint priorProgram = mState.currentProgram;

+    mState.currentProgram = program;               // Must switch before trying to delete, otherwise it only gets flagged.

+

+    if(priorProgram != program)

+    {

+        Program *newProgram = mResourceManager->getProgram(program);

+        Program *oldProgram = mResourceManager->getProgram(priorProgram);

+

+        if(newProgram)

+        {

+            newProgram->addRef();

+        }

+        

+        if(oldProgram)

+        {

+            oldProgram->release();

+        }

+    }

+}

+

+void Context::beginQuery(GLenum target, GLuint query)

+{

+    // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>  

+    // of zero, if the active query object name for <target> is non-zero (for the  

+    // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if  

+    // the active query for either target is non-zero), if <id> is the name of an 

+    // existing query object whose type does not match <target>, or if <id> is the

+    // active query object name for any query type, the error INVALID_OPERATION is

+    // generated.

+

+    // Ensure no other queries are active

+    // NOTE: If other queries than occlusion are supported, we will need to check

+    // separately that:

+    //    a) The query ID passed is not the current active query for any target/type

+    //    b) There are no active queries for the requested target (and in the case

+    //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,

+    //       no query may be active for either if glBeginQuery targets either.

+    for(int i = 0; i < QUERY_TYPE_COUNT; i++)

+    {

+        if(mState.activeQuery[i].get() != NULL)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+    }

+

+    QueryType qType;

+    switch(target)

+    {

+    case GL_ANY_SAMPLES_PASSED_EXT: 

+        qType = QUERY_ANY_SAMPLES_PASSED; 

+        break;

+    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: 

+        qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; 

+        break;

+    default: 

+        ASSERT(false);

+    }

+

+    Query *queryObject = getQuery(query, true, target);

+

+    // Check that name was obtained with glGenQueries

+    if(!queryObject)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    // Check for type mismatch

+    if(queryObject->getType() != target)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    // Set query as active for specified target

+    mState.activeQuery[qType].set(queryObject);

+

+    // Begin query

+    queryObject->begin();

+}

+

+void Context::endQuery(GLenum target)

+{

+    QueryType qType;

+

+    switch(target)

+    {

+    case GL_ANY_SAMPLES_PASSED_EXT: 

+        qType = QUERY_ANY_SAMPLES_PASSED; 

+        break;

+    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: 

+        qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; 

+        break;

+    default: 

+        ASSERT(false);

+    }

+

+    Query *queryObject = mState.activeQuery[qType].get();

+

+    if(queryObject == NULL)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    queryObject->end();

+

+    mState.activeQuery[qType].set(NULL);

+}

+

+void Context::setFramebufferZero(Framebuffer *buffer)

+{

+    delete mFramebufferMap[0];

+    mFramebufferMap[0] = buffer;

+}

+

+void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer)

+{

+    Renderbuffer *renderbufferObject = mState.renderbuffer.get();

+    renderbufferObject->setStorage(renderbuffer);

+}

+

+Framebuffer *Context::getFramebuffer(unsigned int handle)

+{

+    FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle);

+

+    if(framebuffer == mFramebufferMap.end())

+    {

+        return NULL;

+    }

+    else

+    {

+        return framebuffer->second;

+    }

+}

+

+Fence *Context::getFence(unsigned int handle)

+{

+    FenceMap::iterator fence = mFenceMap.find(handle);

+

+    if(fence == mFenceMap.end())

+    {

+        return NULL;

+    }

+    else

+    {

+        return fence->second;

+    }

+}

+

+Query *Context::getQuery(unsigned int handle, bool create, GLenum type)

+{

+    QueryMap::iterator query = mQueryMap.find(handle);

+

+    if(query == mQueryMap.end())

+    {

+        return NULL;

+    }

+    else

+    {

+        if(!query->second && create)

+        {

+            query->second = new Query(handle, type);

+            query->second->addRef();

+        }

+

+        return query->second;

+    }

+}

+

+Buffer *Context::getArrayBuffer()

+{

+    return mState.arrayBuffer.get();

+}

+

+Buffer *Context::getElementArrayBuffer()

+{

+    return mState.elementArrayBuffer.get();

+}

+

+Program *Context::getCurrentProgram()

+{

+    return mResourceManager->getProgram(mState.currentProgram);

+}

+

+Texture2D *Context::getTexture2D()

+{

+    return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));

+}

+

+TextureCubeMap *Context::getTextureCubeMap()

+{

+    return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));

+}

+

+TextureExternal *Context::getTextureExternal()

+{

+    return static_cast<TextureExternal*>(getSamplerTexture(mState.activeSampler, TEXTURE_EXTERNAL));

+}

+

+Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type)

+{

+    GLuint texid = mState.samplerTexture[type][sampler].id();

+

+    if(texid == 0)   // Special case: 0 refers to different initial textures based on the target

+    {

+        switch (type)

+        {

+        case TEXTURE_2D: return mTexture2DZero.get();

+        case TEXTURE_CUBE: return mTextureCubeMapZero.get();

+        case TEXTURE_EXTERNAL: return mTextureExternalZero.get();

+        default: UNREACHABLE();

+        }

+    }

+

+    return mState.samplerTexture[type][sampler].get();

+}

+

+bool Context::getBooleanv(GLenum pname, GLboolean *params)

+{

+    switch (pname)

+    {

+      case GL_SHADER_COMPILER:          *params = GL_TRUE;                          break;

+      case GL_SAMPLE_COVERAGE_INVERT:   *params = mState.sampleCoverageInvert;      break;

+      case GL_DEPTH_WRITEMASK:          *params = mState.depthMask;                 break;

+      case GL_COLOR_WRITEMASK:

+        params[0] = mState.colorMaskRed;

+        params[1] = mState.colorMaskGreen;

+        params[2] = mState.colorMaskBlue;

+        params[3] = mState.colorMaskAlpha;

+        break;

+      case GL_CULL_FACE:                *params = mState.cullFace;                  break;

+      case GL_POLYGON_OFFSET_FILL:      *params = mState.polygonOffsetFill;         break;

+      case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage;     break;

+      case GL_SAMPLE_COVERAGE:          *params = mState.sampleCoverage;            break;

+      case GL_SCISSOR_TEST:             *params = mState.scissorTest;               break;

+      case GL_STENCIL_TEST:             *params = mState.stencilTest;               break;

+      case GL_DEPTH_TEST:               *params = mState.depthTest;                 break;

+      case GL_BLEND:                    *params = mState.blend;                     break;

+      case GL_DITHER:                   *params = mState.dither;                    break;

+      default:

+        return false;

+    }

+

+    return true;

+}

+

+bool Context::getFloatv(GLenum pname, GLfloat *params)

+{

+    // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation

+    // because it is stored as a float, despite the fact that the GL ES 2.0 spec names

+    // GetIntegerv as its native query function. As it would require conversion in any

+    // case, this should make no difference to the calling application.

+    switch (pname)

+    {

+      case GL_LINE_WIDTH:               *params = mState.lineWidth;            break;

+      case GL_SAMPLE_COVERAGE_VALUE:    *params = mState.sampleCoverageValue;  break;

+      case GL_DEPTH_CLEAR_VALUE:        *params = mState.depthClearValue;      break;

+      case GL_POLYGON_OFFSET_FACTOR:    *params = mState.polygonOffsetFactor;  break;

+      case GL_POLYGON_OFFSET_UNITS:     *params = mState.polygonOffsetUnits;   break;

+      case GL_ALIASED_LINE_WIDTH_RANGE:

+        params[0] = ALIASED_LINE_WIDTH_RANGE_MIN;

+        params[1] = ALIASED_LINE_WIDTH_RANGE_MAX;

+        break;

+      case GL_ALIASED_POINT_SIZE_RANGE:

+        params[0] = ALIASED_POINT_SIZE_RANGE_MIN;

+        params[1] = ALIASED_POINT_SIZE_RANGE_MAX;

+        break;

+      case GL_DEPTH_RANGE:

+        params[0] = mState.zNear;

+        params[1] = mState.zFar;

+        break;

+      case GL_COLOR_CLEAR_VALUE:

+        params[0] = mState.colorClearValue.red;

+        params[1] = mState.colorClearValue.green;

+        params[2] = mState.colorClearValue.blue;

+        params[3] = mState.colorClearValue.alpha;

+        break;

+      case GL_BLEND_COLOR:

+        params[0] = mState.blendColor.red;

+        params[1] = mState.blendColor.green;

+        params[2] = mState.blendColor.blue;

+        params[3] = mState.blendColor.alpha;

+        break;

+	  case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:

+        *params = MAX_TEXTURE_MAX_ANISOTROPY;

+		break;

+      default:

+        return false;

+    }

+

+    return true;

+}

+

+bool Context::getIntegerv(GLenum pname, GLint *params)

+{

+    // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation

+    // because it is stored as a float, despite the fact that the GL ES 2.0 spec names

+    // GetIntegerv as its native query function. As it would require conversion in any

+    // case, this should make no difference to the calling application. You may find it in 

+    // Context::getFloatv.

+    switch (pname)

+    {

+    case GL_MAX_VERTEX_ATTRIBS:               *params = MAX_VERTEX_ATTRIBS;               break;

+    case GL_MAX_VERTEX_UNIFORM_VECTORS:       *params = MAX_VERTEX_UNIFORM_VECTORS;       break;

+    case GL_MAX_VARYING_VECTORS:              *params = MAX_VARYING_VECTORS;              break;

+    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = MAX_COMBINED_TEXTURE_IMAGE_UNITS; break;

+    case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:   *params = MAX_VERTEX_TEXTURE_IMAGE_UNITS;   break;

+    case GL_MAX_TEXTURE_IMAGE_UNITS:          *params = MAX_TEXTURE_IMAGE_UNITS;          break;

+	case GL_MAX_FRAGMENT_UNIFORM_VECTORS:     *params = MAX_FRAGMENT_UNIFORM_VECTORS;     break;

+	case GL_MAX_RENDERBUFFER_SIZE:            *params = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE; break;

+    case GL_NUM_SHADER_BINARY_FORMATS:        *params = 0;                                    break;

+    case GL_SHADER_BINARY_FORMATS:      /* no shader binary formats are supported */          break;

+    case GL_ARRAY_BUFFER_BINDING:             *params = mState.arrayBuffer.id();              break;

+    case GL_ELEMENT_ARRAY_BUFFER_BINDING:     *params = mState.elementArrayBuffer.id();       break;

+//	case GL_FRAMEBUFFER_BINDING:            // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE

+    case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE:   *params = mState.drawFramebuffer;               break;

+    case GL_READ_FRAMEBUFFER_BINDING_ANGLE:   *params = mState.readFramebuffer;               break;

+    case GL_RENDERBUFFER_BINDING:             *params = mState.renderbuffer.id();             break;

+    case GL_CURRENT_PROGRAM:                  *params = mState.currentProgram;                break;

+    case GL_PACK_ALIGNMENT:                   *params = mState.packAlignment;                 break;

+    case GL_UNPACK_ALIGNMENT:                 *params = mState.unpackAlignment;               break;

+    case GL_GENERATE_MIPMAP_HINT:             *params = mState.generateMipmapHint;            break;

+    case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break;

+    case GL_ACTIVE_TEXTURE:                   *params = (mState.activeSampler + GL_TEXTURE0); break;

+    case GL_STENCIL_FUNC:                     *params = mState.stencilFunc;                   break;

+    case GL_STENCIL_REF:                      *params = mState.stencilRef;                    break;

+    case GL_STENCIL_VALUE_MASK:               *params = mState.stencilMask;                   break;

+    case GL_STENCIL_BACK_FUNC:                *params = mState.stencilBackFunc;               break;

+    case GL_STENCIL_BACK_REF:                 *params = mState.stencilBackRef;                break;

+    case GL_STENCIL_BACK_VALUE_MASK:          *params = mState.stencilBackMask;               break;

+    case GL_STENCIL_FAIL:                     *params = mState.stencilFail;                   break;

+    case GL_STENCIL_PASS_DEPTH_FAIL:          *params = mState.stencilPassDepthFail;          break;

+    case GL_STENCIL_PASS_DEPTH_PASS:          *params = mState.stencilPassDepthPass;          break;

+    case GL_STENCIL_BACK_FAIL:                *params = mState.stencilBackFail;               break;

+    case GL_STENCIL_BACK_PASS_DEPTH_FAIL:     *params = mState.stencilBackPassDepthFail;      break;

+    case GL_STENCIL_BACK_PASS_DEPTH_PASS:     *params = mState.stencilBackPassDepthPass;      break;

+    case GL_DEPTH_FUNC:                       *params = mState.depthFunc;                     break;

+    case GL_BLEND_SRC_RGB:                    *params = mState.sourceBlendRGB;                break;

+    case GL_BLEND_SRC_ALPHA:                  *params = mState.sourceBlendAlpha;              break;

+    case GL_BLEND_DST_RGB:                    *params = mState.destBlendRGB;                  break;

+    case GL_BLEND_DST_ALPHA:                  *params = mState.destBlendAlpha;                break;

+    case GL_BLEND_EQUATION_RGB:               *params = mState.blendEquationRGB;              break;

+    case GL_BLEND_EQUATION_ALPHA:             *params = mState.blendEquationAlpha;            break;

+    case GL_STENCIL_WRITEMASK:                *params = mState.stencilWritemask;              break;

+    case GL_STENCIL_BACK_WRITEMASK:           *params = mState.stencilBackWritemask;          break;

+    case GL_STENCIL_CLEAR_VALUE:              *params = mState.stencilClearValue;             break;

+    case GL_SUBPIXEL_BITS:                    *params = 4;                                    break;

+	case GL_MAX_TEXTURE_SIZE:                 *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;  break;

+	case GL_MAX_CUBE_MAP_TEXTURE_SIZE:        *params = IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE; break;

+    case GL_NUM_COMPRESSED_TEXTURE_FORMATS:   

+        {

+            if(S3TC_SUPPORT)

+            {

+                // GL_COMPRESSED_RGB_S3TC_DXT1_EXT

+                // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT

+				// GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE

+				// GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE

+                *params = 4;

+            }

+            else

+            {

+                *params = 0;

+            }

+        }

+        break;

+	case GL_MAX_SAMPLES_ANGLE:                *params = IMPLEMENTATION_MAX_SAMPLES; break;

+    case GL_SAMPLE_BUFFERS:                   

+    case GL_SAMPLES:

+        {

+            Framebuffer *framebuffer = getDrawFramebuffer();

+			int width, height, samples;

+

+            if(framebuffer->completeness(width, height, samples) == GL_FRAMEBUFFER_COMPLETE)

+            {

+                switch(pname)

+                {

+                case GL_SAMPLE_BUFFERS:

+                    if(samples > 1)

+                    {

+                        *params = 1;

+                    }

+                    else

+                    {

+                        *params = 0;

+                    }

+                    break;

+                case GL_SAMPLES:

+                    *params = samples & ~1;

+                    break;

+                }

+            }

+            else

+            {

+                *params = 0;

+            }

+        }

+        break;

+    case GL_IMPLEMENTATION_COLOR_READ_TYPE:   *params = IMPLEMENTATION_COLOR_READ_TYPE;   break;

+    case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = IMPLEMENTATION_COLOR_READ_FORMAT; break;

+    case GL_MAX_VIEWPORT_DIMS:

+        {

+			int maxDimension = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE;

+            params[0] = maxDimension;

+            params[1] = maxDimension;

+        }

+        break;

+    case GL_COMPRESSED_TEXTURE_FORMATS:

+        {

+            if(S3TC_SUPPORT)

+            {

+                params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;

+                params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;

+				params[2] = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;

+                params[3] = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;

+            }

+        }

+        break;

+    case GL_VIEWPORT:

+        params[0] = mState.viewportX;

+        params[1] = mState.viewportY;

+        params[2] = mState.viewportWidth;

+        params[3] = mState.viewportHeight;

+        break;

+    case GL_SCISSOR_BOX:

+        params[0] = mState.scissorX;

+        params[1] = mState.scissorY;

+        params[2] = mState.scissorWidth;

+        params[3] = mState.scissorHeight;

+        break;

+    case GL_CULL_FACE_MODE:                   *params = mState.cullMode;                 break;

+    case GL_FRONT_FACE:                       *params = mState.frontFace;                break;

+    case GL_RED_BITS:

+    case GL_GREEN_BITS:

+    case GL_BLUE_BITS:

+    case GL_ALPHA_BITS:

+        {

+            Framebuffer *framebuffer = getDrawFramebuffer();

+            Renderbuffer *colorbuffer = framebuffer->getColorbuffer();

+

+            if(colorbuffer)

+            {

+                switch (pname)

+                {

+                  case GL_RED_BITS:   *params = colorbuffer->getRedSize();   break;

+                  case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break;

+                  case GL_BLUE_BITS:  *params = colorbuffer->getBlueSize();  break;

+                  case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break;

+                }

+            }

+            else

+            {

+                *params = 0;

+            }

+        }

+        break;

+    case GL_DEPTH_BITS:

+        {

+            Framebuffer *framebuffer = getDrawFramebuffer();

+            Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();

+

+            if(depthbuffer)

+            {

+                *params = depthbuffer->getDepthSize();

+            }

+            else

+            {

+                *params = 0;

+            }

+        }

+        break;

+    case GL_STENCIL_BITS:

+        {

+            Framebuffer *framebuffer = getDrawFramebuffer();

+            Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();

+

+            if(stencilbuffer)

+            {

+                *params = stencilbuffer->getStencilSize();

+            }

+            else

+            {

+                *params = 0;

+            }

+        }

+        break;

+    case GL_TEXTURE_BINDING_2D:

+        {

+            if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)

+            {

+                error(GL_INVALID_OPERATION);

+                return false;

+            }

+

+            *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id();

+        }

+        break;

+    case GL_TEXTURE_BINDING_CUBE_MAP:

+        {

+            if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)

+            {

+                error(GL_INVALID_OPERATION);

+                return false;

+            }

+

+            *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id();

+        }

+        break;

+    case GL_TEXTURE_BINDING_EXTERNAL_OES:

+        {

+            if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)

+            {

+                error(GL_INVALID_OPERATION);

+                return false;

+            }

+

+            *params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].id();

+        }

+        break;

+    default:

+        return false;

+    }

+

+    return true;

+}

+

+bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams)

+{

+    // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation

+    // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due

+    // to the fact that it is stored internally as a float, and so would require conversion

+    // if returned from Context::getIntegerv. Since this conversion is already implemented 

+    // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we

+    // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling

+    // application.

+    switch (pname)

+    {

+      case GL_COMPRESSED_TEXTURE_FORMATS:

+		{

+            *type = GL_INT;

+            *numParams = S3TC_SUPPORT ? 4 : 0;

+        }

+		break;

+      case GL_SHADER_BINARY_FORMATS:

+        {

+            *type = GL_INT;

+            *numParams = 0;

+        }

+        break;

+      case GL_MAX_VERTEX_ATTRIBS:

+      case GL_MAX_VERTEX_UNIFORM_VECTORS:

+      case GL_MAX_VARYING_VECTORS:

+      case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:

+      case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:

+      case GL_MAX_TEXTURE_IMAGE_UNITS:

+      case GL_MAX_FRAGMENT_UNIFORM_VECTORS:

+      case GL_MAX_RENDERBUFFER_SIZE:

+      case GL_NUM_SHADER_BINARY_FORMATS:

+      case GL_NUM_COMPRESSED_TEXTURE_FORMATS:

+      case GL_ARRAY_BUFFER_BINDING:

+      case GL_FRAMEBUFFER_BINDING:

+      case GL_RENDERBUFFER_BINDING:

+      case GL_CURRENT_PROGRAM:

+      case GL_PACK_ALIGNMENT:

+      case GL_UNPACK_ALIGNMENT:

+      case GL_GENERATE_MIPMAP_HINT:

+      case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:

+      case GL_RED_BITS:

+      case GL_GREEN_BITS:

+      case GL_BLUE_BITS:

+      case GL_ALPHA_BITS:

+      case GL_DEPTH_BITS:

+      case GL_STENCIL_BITS:

+      case GL_ELEMENT_ARRAY_BUFFER_BINDING:

+      case GL_CULL_FACE_MODE:

+      case GL_FRONT_FACE:

+      case GL_ACTIVE_TEXTURE:

+      case GL_STENCIL_FUNC:

+      case GL_STENCIL_VALUE_MASK:

+      case GL_STENCIL_REF:

+      case GL_STENCIL_FAIL:

+      case GL_STENCIL_PASS_DEPTH_FAIL:

+      case GL_STENCIL_PASS_DEPTH_PASS:

+      case GL_STENCIL_BACK_FUNC:

+      case GL_STENCIL_BACK_VALUE_MASK:

+      case GL_STENCIL_BACK_REF:

+      case GL_STENCIL_BACK_FAIL:

+      case GL_STENCIL_BACK_PASS_DEPTH_FAIL:

+      case GL_STENCIL_BACK_PASS_DEPTH_PASS:

+      case GL_DEPTH_FUNC:

+      case GL_BLEND_SRC_RGB:

+      case GL_BLEND_SRC_ALPHA:

+      case GL_BLEND_DST_RGB:

+      case GL_BLEND_DST_ALPHA:

+      case GL_BLEND_EQUATION_RGB:

+      case GL_BLEND_EQUATION_ALPHA:

+      case GL_STENCIL_WRITEMASK:

+      case GL_STENCIL_BACK_WRITEMASK:

+      case GL_STENCIL_CLEAR_VALUE:

+      case GL_SUBPIXEL_BITS:

+      case GL_MAX_TEXTURE_SIZE:

+      case GL_MAX_CUBE_MAP_TEXTURE_SIZE:

+      case GL_SAMPLE_BUFFERS:

+      case GL_SAMPLES:

+      case GL_IMPLEMENTATION_COLOR_READ_TYPE:

+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT:

+      case GL_TEXTURE_BINDING_2D:

+      case GL_TEXTURE_BINDING_CUBE_MAP:

+      case GL_TEXTURE_BINDING_EXTERNAL_OES:

+        {

+            *type = GL_INT;

+            *numParams = 1;

+        }

+        break;

+      case GL_MAX_SAMPLES_ANGLE:

+        {

+            *type = GL_INT;

+            *numParams = 1;

+        }

+        break;

+      case GL_MAX_VIEWPORT_DIMS:

+        {

+            *type = GL_INT;

+            *numParams = 2;

+        }

+        break;

+      case GL_VIEWPORT:

+      case GL_SCISSOR_BOX:

+        {

+            *type = GL_INT;

+            *numParams = 4;

+        }

+        break;

+      case GL_SHADER_COMPILER:

+      case GL_SAMPLE_COVERAGE_INVERT:

+      case GL_DEPTH_WRITEMASK:

+      case GL_CULL_FACE:                // CULL_FACE through DITHER are natural to IsEnabled,

+      case GL_POLYGON_OFFSET_FILL:      // but can be retrieved through the Get{Type}v queries.

+      case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural

+      case GL_SAMPLE_COVERAGE:

+      case GL_SCISSOR_TEST:

+      case GL_STENCIL_TEST:

+      case GL_DEPTH_TEST:

+      case GL_BLEND:

+      case GL_DITHER:

+        {

+            *type = GL_BOOL;

+            *numParams = 1;

+        }

+        break;

+      case GL_COLOR_WRITEMASK:

+        {

+            *type = GL_BOOL;

+            *numParams = 4;

+        }

+        break;

+      case GL_POLYGON_OFFSET_FACTOR:

+      case GL_POLYGON_OFFSET_UNITS:

+      case GL_SAMPLE_COVERAGE_VALUE:

+      case GL_DEPTH_CLEAR_VALUE:

+      case GL_LINE_WIDTH:

+        {

+            *type = GL_FLOAT;

+            *numParams = 1;

+        }

+        break;

+      case GL_ALIASED_LINE_WIDTH_RANGE:

+      case GL_ALIASED_POINT_SIZE_RANGE:

+      case GL_DEPTH_RANGE:

+        {

+            *type = GL_FLOAT;

+            *numParams = 2;

+        }

+        break;

+      case GL_COLOR_CLEAR_VALUE:

+      case GL_BLEND_COLOR:

+        {

+            *type = GL_FLOAT;

+            *numParams = 4;

+        }

+        break;

+	  case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:

+        *type = GL_FLOAT;

+        *numParams = 1;

+        break;

+      default:

+        return false;

+    }

+

+    return true;

+}

+

+// Applies the render target surface, depth stencil surface, viewport rectangle and scissor rectangle

+bool Context::applyRenderTarget()

+{

+    Device *device = getDevice();

+    Framebuffer *framebuffer = getDrawFramebuffer();

+	int width, height, samples;

+

+    if(!framebuffer || framebuffer->completeness(width, height, samples) != GL_FRAMEBUFFER_COMPLETE)

+    {

+        return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);

+    }

+

+    Image *renderTarget = framebuffer->getRenderTarget();

+	device->setRenderTarget(renderTarget);

+	if(renderTarget) renderTarget->release();

+

+    Image *depthStencil = framebuffer->getDepthStencil();

+    device->setDepthStencilSurface(depthStencil);

+	if(depthStencil) depthStencil->release();

+

+    Viewport viewport;

+    float zNear = clamp01(mState.zNear);

+    float zFar = clamp01(mState.zFar);

+

+    viewport.x0 = mState.viewportX;

+    viewport.y0 = mState.viewportY;

+    viewport.width = mState.viewportWidth;

+    viewport.height = mState.viewportHeight;

+    viewport.minZ = zNear;

+    viewport.maxZ = zFar;

+

+    device->setViewport(viewport);

+

+    if(mState.scissorTest)

+    {

+		sw::Rect scissor = {mState.scissorX, mState.scissorY, mState.scissorX + mState.scissorWidth, mState.scissorY + mState.scissorHeight};

+		scissor.clip(0, 0, width, height);

+        

+		device->setScissorRect(scissor);

+        device->setScissorEnable(true);

+    }

+    else

+    {

+        device->setScissorEnable(false);

+    }

+

+	Program *program = getCurrentProgram();

+

+	if(program)

+	{

+		GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear};

+        program->setUniform1fv(program->getUniformLocation("gl_DepthRange.near"), 1, &nearFarDiff[0]);

+		program->setUniform1fv(program->getUniformLocation("gl_DepthRange.far"), 1, &nearFarDiff[1]);

+		program->setUniform1fv(program->getUniformLocation("gl_DepthRange.diff"), 1, &nearFarDiff[2]);

+    }

+

+    return true;

+}

+

+// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc)

+void Context::applyState(GLenum drawMode)

+{

+    Device *device = getDevice();

+    Framebuffer *framebuffer = getDrawFramebuffer();

+

+    if(mState.cullFace)

+    {

+        device->setCullMode(es2sw::ConvertCullMode(mState.cullMode, mState.frontFace));

+    }

+    else

+    {

+		device->setCullMode(sw::CULL_NONE);

+    }

+

+    if(mDepthStateDirty)

+    {

+        if(mState.depthTest)

+        {

+			device->setDepthBufferEnable(true);

+			device->setDepthCompare(es2sw::ConvertDepthComparison(mState.depthFunc));

+        }

+        else

+        {

+            device->setDepthBufferEnable(false);

+        }

+

+        mDepthStateDirty = false;

+    }

+

+    if(mBlendStateDirty)

+    {

+        if(mState.blend)

+        {

+			device->setAlphaBlendEnable(true);

+			device->setSeparateAlphaBlendEnable(true);

+

+            device->setBlendConstant(es2sw::ConvertColor(mState.blendColor));

+

+			device->setSourceBlendFactor(es2sw::ConvertBlendFunc(mState.sourceBlendRGB));

+			device->setDestBlendFactor(es2sw::ConvertBlendFunc(mState.destBlendRGB));

+			device->setBlendOperation(es2sw::ConvertBlendOp(mState.blendEquationRGB));

+

+            device->setSourceBlendFactorAlpha(es2sw::ConvertBlendFunc(mState.sourceBlendAlpha));

+			device->setDestBlendFactorAlpha(es2sw::ConvertBlendFunc(mState.destBlendAlpha));

+			device->setBlendOperationAlpha(es2sw::ConvertBlendOp(mState.blendEquationAlpha));

+        }

+        else

+        {

+			device->setAlphaBlendEnable(false);

+        }

+

+        mBlendStateDirty = false;

+    }

+

+    if(mStencilStateDirty || mFrontFaceDirty)

+    {

+        if(mState.stencilTest && framebuffer->hasStencil())

+        {

+			device->setStencilEnable(true);

+			device->setTwoSidedStencil(true);

+

+            if(mState.stencilWritemask != mState.stencilBackWritemask || 

+               mState.stencilRef != mState.stencilBackRef || 

+               mState.stencilMask != mState.stencilBackMask)

+            {

+				ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL.");

+                return error(GL_INVALID_OPERATION);

+            }

+

+            // get the maximum size of the stencil ref

+            Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();

+            GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;

+

+			if(mState.frontFace == GL_CCW)

+			{

+				device->setStencilWriteMask(mState.stencilWritemask);

+				device->setStencilCompare(es2sw::ConvertStencilComparison(mState.stencilFunc));

+

+				device->setStencilReference((mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);

+				device->setStencilMask(mState.stencilMask);

+

+				device->setStencilFailOperation(es2sw::ConvertStencilOp(mState.stencilFail));

+				device->setStencilZFailOperation(es2sw::ConvertStencilOp(mState.stencilPassDepthFail));

+				device->setStencilPassOperation(es2sw::ConvertStencilOp(mState.stencilPassDepthPass));

+

+				device->setStencilWriteMaskCCW(mState.stencilBackWritemask);

+				device->setStencilCompareCCW(es2sw::ConvertStencilComparison(mState.stencilBackFunc));

+

+				device->setStencilReferenceCCW((mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);

+				device->setStencilMaskCCW(mState.stencilBackMask);

+

+				device->setStencilFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackFail));

+				device->setStencilZFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackPassDepthFail));

+				device->setStencilPassOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackPassDepthPass));

+			}

+			else

+			{

+				device->setStencilWriteMaskCCW(mState.stencilWritemask);

+				device->setStencilCompareCCW(es2sw::ConvertStencilComparison(mState.stencilFunc));

+

+				device->setStencilReferenceCCW((mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);

+				device->setStencilMaskCCW(mState.stencilMask);

+

+				device->setStencilFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilFail));

+				device->setStencilZFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilPassDepthFail));

+				device->setStencilPassOperationCCW(es2sw::ConvertStencilOp(mState.stencilPassDepthPass));

+

+				device->setStencilWriteMask(mState.stencilBackWritemask);

+				device->setStencilCompare(es2sw::ConvertStencilComparison(mState.stencilBackFunc));

+

+				device->setStencilReference((mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);

+				device->setStencilMask(mState.stencilBackMask);

+

+				device->setStencilFailOperation(es2sw::ConvertStencilOp(mState.stencilBackFail));

+				device->setStencilZFailOperation(es2sw::ConvertStencilOp(mState.stencilBackPassDepthFail));

+				device->setStencilPassOperation(es2sw::ConvertStencilOp(mState.stencilBackPassDepthPass));

+			}

+        }

+        else

+        {

+			device->setStencilEnable(false);

+        }

+

+        mStencilStateDirty = false;

+        mFrontFaceDirty = false;

+    }

+

+    if(mMaskStateDirty)

+    {

+		device->setColorWriteMask(0, es2sw::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));

+		device->setDepthWriteEnable(mState.depthMask);

+

+        mMaskStateDirty = false;

+    }

+

+    if(mPolygonOffsetStateDirty)

+    {

+        if(mState.polygonOffsetFill)

+        {

+            Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();

+            if(depthbuffer)

+            {

+				device->setSlopeDepthBias(mState.polygonOffsetFactor);

+                float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));

+				device->setDepthBias(depthBias);

+            }

+        }

+        else

+        {

+            device->setSlopeDepthBias(0);

+            device->setDepthBias(0);

+        }

+

+        mPolygonOffsetStateDirty = false;

+    }

+

+    if(mSampleStateDirty)

+    {

+        if(mState.sampleAlphaToCoverage)

+        {

+            device->setTransparencyAntialiasing(sw::TRANSPARENCY_ALPHA_TO_COVERAGE);

+        }

+		else

+		{

+			device->setTransparencyAntialiasing(sw::TRANSPARENCY_NONE);

+		}

+

+        if(mState.sampleCoverage)

+        {

+            unsigned int mask = 0;

+            if(mState.sampleCoverageValue != 0)

+            {

+				int width, height, samples;

+				framebuffer->completeness(width, height, samples);

+

+                float threshold = 0.5f;

+

+                for(int i = 0; i < samples; i++)

+                {

+                    mask <<= 1;

+

+                    if((i + 1) * mState.sampleCoverageValue >= threshold)

+                    {

+                        threshold += 1.0f;

+                        mask |= 1;

+                    }

+                }

+            }

+            

+            if(mState.sampleCoverageInvert)

+            {

+                mask = ~mask;

+            }

+

+			device->setMultiSampleMask(mask);

+        }

+        else

+        {

+			device->setMultiSampleMask(0xFFFFFFFF);

+        }

+

+        mSampleStateDirty = false;

+    }

+

+    if(mDitherStateDirty)

+    {

+    //	UNIMPLEMENTED();   // FIXME

+

+        mDitherStateDirty = false;

+    }

+}

+

+GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count)

+{

+    TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];

+

+    GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes);

+    if(err != GL_NO_ERROR)

+    {

+        return err;

+    }

+

+    Device *device = getDevice();

+	Program *program = getCurrentProgram();

+

+	device->resetInputStreams(false);

+

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+	{

+		if(program->getAttributeStream(i) == -1)

+		{

+			continue;

+		}

+

+		sw::Resource *resource = attributes[i].vertexBuffer;

+		const void *buffer = (char*)resource->getBuffer() + attributes[i].offset;

+			

+		int stride = attributes[i].stride;

+

+		buffer = (char*)buffer + stride * base;

+

+		sw::Stream attribute(resource, buffer, stride);

+

+		attribute.type = attributes[i].type;

+		attribute.count = attributes[i].count;

+		attribute.normalized = attributes[i].normalized;

+

+		int stream = program->getAttributeStream(i);

+		device->setInputStream(stream, attribute);

+	}

+

+	return GL_NO_ERROR;

+}

+

+// Applies the indices and element array bindings

+GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)

+{

+    Device *device = getDevice();

+    GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);

+

+    if(err == GL_NO_ERROR)

+    {

+        device->setIndexBuffer(indexInfo->indexBuffer);

+    }

+

+    return err;

+}

+

+// Applies the shaders and shader constants

+void Context::applyShaders()

+{

+    Device *device = getDevice();

+    Program *programObject = getCurrentProgram();

+    sw::VertexShader *vertexShader = programObject->getVertexShader();

+	sw::PixelShader *pixelShader = programObject->getPixelShader();

+

+    device->setVertexShader(vertexShader);

+    device->setPixelShader(pixelShader);

+

+    if(programObject->getSerial() != mAppliedProgramSerial)

+    {

+        programObject->dirtyAllUniforms();

+        mAppliedProgramSerial = programObject->getSerial();

+    }

+

+    programObject->applyUniforms();

+}

+

+void Context::applyTextures()

+{

+    applyTextures(sw::SAMPLER_PIXEL);

+	applyTextures(sw::SAMPLER_VERTEX);

+}

+

+void Context::applyTextures(sw::SamplerType samplerType)

+{

+    Device *device = getDevice();

+    Program *programObject = getCurrentProgram();

+

+    int samplerCount = (samplerType == sw::SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS;   // Range of samplers of given sampler type

+

+    for(int samplerIndex = 0; samplerIndex < samplerCount; samplerIndex++)

+    {

+        int textureUnit = programObject->getSamplerMapping(samplerType, samplerIndex);   // OpenGL texture image unit index

+

+        if(textureUnit != -1)

+        {

+            TextureType textureType = programObject->getSamplerTextureType(samplerType, samplerIndex);

+

+            Texture *texture = getSamplerTexture(textureUnit, textureType);

+

+			if(texture->isSamplerComplete())

+            {

+                GLenum wrapS = texture->getWrapS();

+                GLenum wrapT = texture->getWrapT();

+                GLenum texFilter = texture->getMinFilter();

+                GLenum magFilter = texture->getMagFilter();

+				GLenum maxAnisotropy = texture->getMaxAnisotropy();

+

+				device->setAddressingModeU(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapS));

+                device->setAddressingModeV(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapT));

+

+				sw::FilterType minFilter;

+				sw::MipmapType mipFilter;

+                es2sw::ConvertMinFilter(texFilter, &minFilter, &mipFilter, maxAnisotropy);

+			//	ASSERT(minFilter == es2sw::ConvertMagFilter(magFilter));

+

+				device->setTextureFilter(samplerType, samplerIndex, minFilter);

+			//	device->setTextureFilter(samplerType, samplerIndex, es2sw::ConvertMagFilter(magFilter));

+				device->setMipmapFilter(samplerType, samplerIndex, mipFilter);

+				device->setMaxAnisotropy(samplerType, samplerIndex, maxAnisotropy);                

+

+				applyTexture(samplerType, samplerIndex, texture);

+            }

+            else

+            {

+                applyTexture(samplerType, samplerIndex, 0);

+            }

+        }

+        else

+        {

+            applyTexture(samplerType, samplerIndex, NULL);

+        }

+    }

+}

+

+void Context::applyTexture(sw::SamplerType type, int index, Texture *baseTexture)

+{

+	Device *device = getDevice();

+	Program *program = getCurrentProgram();

+	int sampler = (type == sw::SAMPLER_PIXEL) ? index : 16 + index;

+	bool textureUsed = false;

+

+	if(type == sw::SAMPLER_PIXEL)

+	{

+		textureUsed = program->getPixelShader()->usesSampler(index);

+	}

+	else if(type == sw::SAMPLER_VERTEX)

+	{

+		textureUsed = program->getVertexShader()->usesSampler(index);

+	}

+	else UNREACHABLE();

+

+	sw::Resource *resource = 0;

+

+	if(baseTexture && textureUsed)

+	{

+		resource = baseTexture->getResource();

+	}

+

+	device->setTextureResource(sampler, resource);

+			

+	if(baseTexture && textureUsed)

+	{

+		int levelCount = baseTexture->getLevelCount();

+

+		if(baseTexture->getTarget() == GL_TEXTURE_2D || baseTexture->getTarget() == GL_TEXTURE_EXTERNAL_OES)

+		{

+			Texture2D *texture = static_cast<Texture2D*>(baseTexture);

+

+			for(int mipmapLevel = 0; mipmapLevel < MIPMAP_LEVELS; mipmapLevel++)

+			{

+				int surfaceLevel = mipmapLevel;

+

+				if(surfaceLevel < 0)

+				{

+					surfaceLevel = 0;

+				}

+				else if(surfaceLevel >= levelCount)

+				{

+					surfaceLevel = levelCount - 1;

+				}

+

+				Image *surface = texture->getImage(surfaceLevel);

+				device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);

+			}

+		}

+		else if(baseTexture->getTarget() == GL_TEXTURE_CUBE_MAP)

+		{

+			for(int face = 0; face < 6; face++)

+			{

+				TextureCubeMap *cubeTexture = static_cast<TextureCubeMap*>(baseTexture);

+

+				for(int mipmapLevel = 0; mipmapLevel < MIPMAP_LEVELS; mipmapLevel++)

+				{

+					int surfaceLevel = mipmapLevel;

+

+					if(surfaceLevel < 0)

+					{

+						surfaceLevel = 0;

+					}

+					else if(surfaceLevel >= levelCount)

+					{

+						surfaceLevel = levelCount - 1;

+					}

+

+					Image *surface = cubeTexture->getImage(face, surfaceLevel);

+					device->setTextureLevel(sampler, face, mipmapLevel, surface, sw::TEXTURE_CUBE);

+				}

+			}

+		}

+		else UNIMPLEMENTED();

+	}

+	else

+	{

+		device->setTextureLevel(sampler, 0, 0, 0, sw::TEXTURE_NULL);

+	}

+}

+

+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,

+                         GLenum format, GLenum type, GLsizei *bufSize, void* pixels)

+{

+    Framebuffer *framebuffer = getReadFramebuffer();

+	int framebufferWidth, framebufferHeight, framebufferSamples;

+

+    if(framebuffer->completeness(framebufferWidth, framebufferHeight, framebufferSamples) != GL_FRAMEBUFFER_COMPLETE)

+    {

+        return error(GL_INVALID_FRAMEBUFFER_OPERATION);

+    }

+

+    if(getReadFramebufferHandle() != 0 && framebufferSamples != 0)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+	GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment);

+    

+	// Sized query sanity check

+    if(bufSize)

+    {

+        int requiredSize = outputPitch * height;

+        if(requiredSize > *bufSize)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+    }

+

+    Image *renderTarget = framebuffer->getRenderTarget();

+

+    if(!renderTarget)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+	sw::Rect rect = {x, y, x + width, y + height};

+	rect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());

+

+    unsigned char *source = (unsigned char*)renderTarget->lock(rect.x0, rect.y0, sw::LOCK_READONLY);

+    unsigned char *dest = (unsigned char*)pixels;

+    unsigned short *dest16 = (unsigned short*)pixels;

+    int inputPitch = (int)renderTarget->getPitch();

+

+    for(int j = 0; j < rect.y1 - rect.y0; j++)

+    {

+        if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&

+           format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)

+        {

+            // Fast path for EXT_read_format_bgra, given an RGBA source buffer

+			// Note that buffers with no alpha go through the slow path below

+            memcpy(dest + j * outputPitch, source + j * inputPitch, (rect.x1 - rect.x0) * 4);

+        }

+		else

+		{

+			for(int i = 0; i < rect.x1 - rect.x0; i++)

+			{

+				float r;

+				float g;

+				float b;

+				float a;

+

+				switch(renderTarget->getInternalFormat())

+				{

+				case sw::FORMAT_R5G6B5:

+					{

+						unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch);

+

+						a = 1.0f;

+						b = (rgb & 0x001F) * (1.0f / 0x001F);

+						g = (rgb & 0x07E0) * (1.0f / 0x07E0);

+						r = (rgb & 0xF800) * (1.0f / 0xF800);

+					}

+					break;

+				case sw::FORMAT_A1R5G5B5:

+					{

+						unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch);

+

+						a = (argb & 0x8000) ? 1.0f : 0.0f;

+						b = (argb & 0x001F) * (1.0f / 0x001F);

+						g = (argb & 0x03E0) * (1.0f / 0x03E0);

+						r = (argb & 0x7C00) * (1.0f / 0x7C00);

+					}

+					break;

+				case sw::FORMAT_A8R8G8B8:

+					{

+						unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);

+

+						a = (argb & 0xFF000000) * (1.0f / 0xFF000000);

+						b = (argb & 0x000000FF) * (1.0f / 0x000000FF);

+						g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);

+						r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);

+					}

+					break;

+				case sw::FORMAT_X8R8G8B8:

+					{

+						unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch);

+

+						a = 1.0f;

+						b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);

+						g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);

+						r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);

+					}

+					break;

+				case sw::FORMAT_A2R10G10B10:

+					{

+						unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);

+

+						a = (argb & 0xC0000000) * (1.0f / 0xC0000000);

+						b = (argb & 0x000003FF) * (1.0f / 0x000003FF);

+						g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);

+						r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);

+					}

+					break;

+				case sw::FORMAT_A32B32G32R32F:

+					{

+						r = *((float*)(source + 16 * i + j * inputPitch) + 0);

+						g = *((float*)(source + 16 * i + j * inputPitch) + 1);

+						b = *((float*)(source + 16 * i + j * inputPitch) + 2);

+						a = *((float*)(source + 16 * i + j * inputPitch) + 3);

+					}

+					break;

+				case sw::FORMAT_A16B16G16R16F:

+					{

+						r = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 0);

+						g = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 1);

+						b = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 2);

+						a = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 3);

+					}

+					break;

+				default:

+					UNIMPLEMENTED();   // FIXME

+					UNREACHABLE();

+				}

+

+				switch(format)

+				{

+				case GL_RGBA:

+					switch(type)

+					{

+					case GL_UNSIGNED_BYTE:

+						dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);

+						dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);

+						dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);

+						dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);

+						break;

+					default: UNREACHABLE();

+					}

+					break;

+				case GL_BGRA_EXT:

+					switch(type)

+					{

+					case GL_UNSIGNED_BYTE:

+						dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f);

+						dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);

+						dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f);

+						dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);

+						break;

+					case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:

+						// According to the desktop GL spec in the "Transfer of Pixel Rectangles" section

+						// this type is packed as follows:

+						//   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0

+						//  --------------------------------------------------------------------------------

+						// |       4th         |        3rd         |        2nd        |   1st component   |

+						//  --------------------------------------------------------------------------------

+						// in the case of BGRA_EXT, B is the first component, G the second, and so forth.

+						dest16[i + j * outputPitch / sizeof(unsigned short)] =

+							((unsigned short)(15 * a + 0.5f) << 12)|

+							((unsigned short)(15 * r + 0.5f) << 8) |

+							((unsigned short)(15 * g + 0.5f) << 4) |

+							((unsigned short)(15 * b + 0.5f) << 0);

+						break;

+					case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:

+						// According to the desktop GL spec in the "Transfer of Pixel Rectangles" section

+						// this type is packed as follows:

+						//   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0

+						//  --------------------------------------------------------------------------------

+						// | 4th |          3rd           |           2nd          |      1st component     |

+						//  --------------------------------------------------------------------------------

+						// in the case of BGRA_EXT, B is the first component, G the second, and so forth.

+						dest16[i + j * outputPitch / sizeof(unsigned short)] =

+							((unsigned short)(     a + 0.5f) << 15) |

+							((unsigned short)(31 * r + 0.5f) << 10) |

+							((unsigned short)(31 * g + 0.5f) << 5) |

+							((unsigned short)(31 * b + 0.5f) << 0);

+						break;

+					default: UNREACHABLE();

+					}

+					break;

+				case GL_RGB:   // IMPLEMENTATION_COLOR_READ_FORMAT

+					switch(type)

+					{

+					case GL_UNSIGNED_SHORT_5_6_5:   // IMPLEMENTATION_COLOR_READ_TYPE

+						dest16[i + j * outputPitch / sizeof(unsigned short)] = 

+							((unsigned short)(31 * b + 0.5f) << 0) |

+							((unsigned short)(63 * g + 0.5f) << 5) |

+							((unsigned short)(31 * r + 0.5f) << 11);

+						break;

+					default: UNREACHABLE();

+					}

+					break;

+				default: UNREACHABLE();

+				}

+			}

+        }

+    }

+

+	renderTarget->unlock();

+	renderTarget->release();

+}

+

+void Context::clear(GLbitfield mask)

+{

+    Framebuffer *framebuffer = getDrawFramebuffer();

+

+    if(!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)

+    {

+        return error(GL_INVALID_FRAMEBUFFER_OPERATION);

+    }

+

+    if(!applyRenderTarget())

+    {

+        return;

+    }

+

+	Device *device = getDevice();

+

+	unsigned int color = (unorm<8>(mState.colorClearValue.alpha) << 24) |

+                         (unorm<8>(mState.colorClearValue.red) << 16) |

+                         (unorm<8>(mState.colorClearValue.green) << 8) | 

+                         (unorm<8>(mState.colorClearValue.blue) << 0);

+    float depth = clamp01(mState.depthClearValue);

+    int stencil = mState.stencilClearValue & 0x000000FF;

+

+	if(mask & GL_COLOR_BUFFER_BIT)

+	{

+		unsigned int rgbaMask = (mState.colorMaskRed ? 0x1 : 0) |

+		                        (mState.colorMaskGreen ? 0x2 : 0) | 

+		                        (mState.colorMaskBlue ? 0x4 : 0) |

+		                        (mState.colorMaskAlpha ? 0x8 : 0);

+

+		if(rgbaMask != 0)

+		{

+			device->clearColor(color, rgbaMask);

+		}

+	}

+

+	if(mask & GL_DEPTH_BUFFER_BIT)

+	{

+		if(mState.depthMask != 0)

+		{

+			device->clearDepth(depth);

+		}

+	}

+

+	if(mask & GL_STENCIL_BUFFER_BIT)

+	{

+		if(mState.stencilWritemask != 0)

+		{

+			device->clearStencil(stencil, mState.stencilWritemask);

+		}

+	}

+}

+

+void Context::drawArrays(GLenum mode, GLint first, GLsizei count)

+{

+    if(!mState.currentProgram)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    Device *device = getDevice();

+    PrimitiveType primitiveType;

+    int primitiveCount;

+

+    if(!es2sw::ConvertPrimitiveType(mode, count, primitiveType, primitiveCount))

+        return error(GL_INVALID_ENUM);

+

+    if(primitiveCount <= 0)

+    {

+        return;

+    }

+

+    if(!applyRenderTarget())

+    {

+        return;

+    }

+

+    applyState(mode);

+

+    GLenum err = applyVertexBuffer(0, first, count);

+    if(err != GL_NO_ERROR)

+    {

+        return error(err);

+    }

+

+    applyShaders();

+    applyTextures();

+

+    if(!getCurrentProgram()->validateSamplers(false))

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(!cullSkipsDraw(mode))

+    {

+        device->drawPrimitive(primitiveType, primitiveCount);

+    }

+}

+

+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)

+{

+    if(!mState.currentProgram)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(!indices && !mState.elementArrayBuffer)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    Device *device = getDevice();

+    PrimitiveType primitiveType;

+    int primitiveCount;

+

+    if(!es2sw::ConvertPrimitiveType(mode, count, primitiveType, primitiveCount))

+        return error(GL_INVALID_ENUM);

+

+    if(primitiveCount <= 0)

+    {

+        return;

+    }

+

+    if(!applyRenderTarget())

+    {

+        return;

+    }

+

+    applyState(mode);

+

+    TranslatedIndexData indexInfo;

+    GLenum err = applyIndexBuffer(indices, count, mode, type, &indexInfo);

+    if(err != GL_NO_ERROR)

+    {

+        return error(err);

+    }

+

+    GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;

+    err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount);

+    if(err != GL_NO_ERROR)

+    {

+        return error(err);

+    }

+

+    applyShaders();

+    applyTextures();

+

+    if(!getCurrentProgram()->validateSamplers(false))

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(!cullSkipsDraw(mode))

+    {

+		device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount, IndexDataManager::typeSize(type));

+    }

+}

+

+void Context::finish()

+{

+	Device *device = getDevice();

+

+	device->finish();

+}

+

+void Context::flush()

+{

+    // We don't queue anything without processing it as fast as possible

+}

+

+void Context::recordInvalidEnum()

+{

+    mInvalidEnum = true;

+}

+

+void Context::recordInvalidValue()

+{

+    mInvalidValue = true;

+}

+

+void Context::recordInvalidOperation()

+{

+    mInvalidOperation = true;

+}

+

+void Context::recordOutOfMemory()

+{

+    mOutOfMemory = true;

+}

+

+void Context::recordInvalidFramebufferOperation()

+{

+    mInvalidFramebufferOperation = true;

+}

+

+// Get one of the recorded errors and clear its flag, if any.

+// [OpenGL ES 2.0.24] section 2.5 page 13.

+GLenum Context::getError()

+{

+    if(mInvalidEnum)

+    {

+        mInvalidEnum = false;

+

+        return GL_INVALID_ENUM;

+    }

+

+    if(mInvalidValue)

+    {

+        mInvalidValue = false;

+

+        return GL_INVALID_VALUE;

+    }

+

+    if(mInvalidOperation)

+    {

+        mInvalidOperation = false;

+

+        return GL_INVALID_OPERATION;

+    }

+

+    if(mOutOfMemory)

+    {

+        mOutOfMemory = false;

+

+        return GL_OUT_OF_MEMORY;

+    }

+

+    if(mInvalidFramebufferOperation)

+    {

+        mInvalidFramebufferOperation = false;

+

+        return GL_INVALID_FRAMEBUFFER_OPERATION;

+    }

+

+    return GL_NO_ERROR;

+}

+

+int Context::getSupportedMultiSampleDepth(sw::Format format, int requested)

+{

+    if(requested <= 1)

+    {

+        return 1;

+    }

+	

+	if(requested == 2)

+	{

+		return 2;

+	}

+	

+	return 4;

+}

+

+void Context::detachBuffer(GLuint buffer)

+{

+    // [OpenGL ES 2.0.24] section 2.9 page 22:

+    // If a buffer object is deleted while it is bound, all bindings to that object in the current context

+    // (i.e. in the thread that called Delete-Buffers) are reset to zero.

+

+    if(mState.arrayBuffer.id() == buffer)

+    {

+        mState.arrayBuffer.set(NULL);

+    }

+

+    if(mState.elementArrayBuffer.id() == buffer)

+    {

+        mState.elementArrayBuffer.set(NULL);

+    }

+

+    for(int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)

+    {

+        if(mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer)

+        {

+            mState.vertexAttribute[attribute].mBoundBuffer.set(NULL);

+        }

+    }

+}

+

+void Context::detachTexture(GLuint texture)

+{

+    // [OpenGL ES 2.0.24] section 3.8 page 84:

+    // If a texture object is deleted, it is as if all texture units which are bound to that texture object are

+    // rebound to texture object zero

+

+    for(int type = 0; type < TEXTURE_TYPE_COUNT; type++)

+    {

+        for(int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++)

+        {

+            if(mState.samplerTexture[type][sampler].id() == texture)

+            {

+                mState.samplerTexture[type][sampler].set(NULL);

+            }

+        }

+    }

+

+    // [OpenGL ES 2.0.24] section 4.4 page 112:

+    // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is

+    // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this

+    // image was attached in the currently bound framebuffer.

+

+    Framebuffer *readFramebuffer = getReadFramebuffer();

+    Framebuffer *drawFramebuffer = getDrawFramebuffer();

+

+    if(readFramebuffer)

+    {

+        readFramebuffer->detachTexture(texture);

+    }

+

+    if(drawFramebuffer && drawFramebuffer != readFramebuffer)

+    {

+        drawFramebuffer->detachTexture(texture);

+    }

+}

+

+void Context::detachFramebuffer(GLuint framebuffer)

+{

+    // [OpenGL ES 2.0.24] section 4.4 page 107:

+    // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though

+    // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.

+

+    if(mState.readFramebuffer == framebuffer)

+    {

+        bindReadFramebuffer(0);

+    }

+

+    if(mState.drawFramebuffer == framebuffer)

+    {

+        bindDrawFramebuffer(0);

+    }

+}

+

+void Context::detachRenderbuffer(GLuint renderbuffer)

+{

+    // [OpenGL ES 2.0.24] section 4.4 page 109:

+    // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer

+    // had been executed with the target RENDERBUFFER and name of zero.

+

+    if(mState.renderbuffer.id() == renderbuffer)

+    {

+        bindRenderbuffer(0);

+    }

+

+    // [OpenGL ES 2.0.24] section 4.4 page 111:

+    // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,

+    // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment

+    // point to which this image was attached in the currently bound framebuffer.

+

+    Framebuffer *readFramebuffer = getReadFramebuffer();

+    Framebuffer *drawFramebuffer = getDrawFramebuffer();

+

+    if(readFramebuffer)

+    {

+        readFramebuffer->detachRenderbuffer(renderbuffer);

+    }

+

+    if(drawFramebuffer && drawFramebuffer != readFramebuffer)

+    {

+        drawFramebuffer->detachRenderbuffer(renderbuffer);

+    }

+}

+

+bool Context::cullSkipsDraw(GLenum drawMode)

+{

+    return mState.cullFace && mState.cullMode == GL_FRONT_AND_BACK && isTriangleMode(drawMode);

+}

+

+bool Context::isTriangleMode(GLenum drawMode)

+{

+    switch (drawMode)

+    {

+      case GL_TRIANGLES:

+      case GL_TRIANGLE_FAN:

+      case GL_TRIANGLE_STRIP:

+        return true;

+      case GL_POINTS:

+      case GL_LINES:

+      case GL_LINE_LOOP:

+      case GL_LINE_STRIP:

+        return false;

+      default: UNREACHABLE();

+    }

+

+    return false;

+}

+

+void Context::setVertexAttrib(GLuint index, const GLfloat *values)

+{

+    ASSERT(index < MAX_VERTEX_ATTRIBS);

+

+    mState.vertexAttribute[index].mCurrentValue[0] = values[0];

+    mState.vertexAttribute[index].mCurrentValue[1] = values[1];

+    mState.vertexAttribute[index].mCurrentValue[2] = values[2];

+    mState.vertexAttribute[index].mCurrentValue[3] = values[3];

+

+    mVertexDataManager->dirtyCurrentValue(index);

+}

+

+void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 

+                              GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,

+                              GLbitfield mask)

+{

+    Device *device = getDevice();

+

+    Framebuffer *readFramebuffer = getReadFramebuffer();

+    Framebuffer *drawFramebuffer = getDrawFramebuffer();

+

+	int readBufferWidth, readBufferHeight, readBufferSamples;

+    int drawBufferWidth, drawBufferHeight, drawBufferSamples;

+

+    if(!readFramebuffer || readFramebuffer->completeness(readBufferWidth, readBufferHeight, readBufferSamples) != GL_FRAMEBUFFER_COMPLETE ||

+       !drawFramebuffer || drawFramebuffer->completeness(drawBufferWidth, drawBufferHeight, drawBufferSamples) != GL_FRAMEBUFFER_COMPLETE)

+    {

+        return error(GL_INVALID_FRAMEBUFFER_OPERATION);

+    }

+

+    if(drawBufferSamples > 1)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    sw::Rect sourceRect;

+    sw::Rect destRect;

+

+    if(srcX0 < srcX1)

+    {

+        sourceRect.x0 = srcX0;

+        sourceRect.x1 = srcX1;

+        destRect.x0 = dstX0;

+        destRect.x1 = dstX1;

+    }

+    else

+    {

+        sourceRect.x0 = srcX1;

+        destRect.x0 = dstX1;

+        sourceRect.x1 = srcX0;

+        destRect.x1 = dstX0;

+    }

+

+    if(srcY0 < srcY1)

+    {

+        sourceRect.y0 = srcY0;

+        destRect.y0 = dstY0;

+        sourceRect.y1 = srcY1;

+        destRect.y1 = dstY1;

+    }

+    else

+    {

+        sourceRect.y0 = srcY1;

+        destRect.y0 = dstY1;

+        sourceRect.y1 = srcY0;

+        destRect.y1 = dstY0;

+    }

+

+    sw::Rect sourceScissoredRect = sourceRect;

+    sw::Rect destScissoredRect = destRect;

+

+    if(mState.scissorTest)   // Only write to parts of the destination framebuffer which pass the scissor test

+    {

+        if(destRect.x0 < mState.scissorX)

+        {

+            int xDiff = mState.scissorX - destRect.x0;

+            destScissoredRect.x0 = mState.scissorX;

+            sourceScissoredRect.x0 += xDiff;

+        }

+

+        if(destRect.x1 > mState.scissorX + mState.scissorWidth)

+        {

+            int xDiff = destRect.x1 - (mState.scissorX + mState.scissorWidth);

+            destScissoredRect.x1 = mState.scissorX + mState.scissorWidth;

+            sourceScissoredRect.x1 -= xDiff;

+        }

+

+        if(destRect.y0 < mState.scissorY)

+        {

+            int yDiff = mState.scissorY - destRect.y0;

+            destScissoredRect.y0 = mState.scissorY;

+            sourceScissoredRect.y0 += yDiff;

+        }

+

+        if(destRect.y1 > mState.scissorY + mState.scissorHeight)

+        {

+            int yDiff = destRect.y1 - (mState.scissorY + mState.scissorHeight);

+            destScissoredRect.y1 = mState.scissorY + mState.scissorHeight;

+            sourceScissoredRect.y1 -= yDiff;

+        }

+    }

+

+    sw::Rect sourceTrimmedRect = sourceScissoredRect;

+    sw::Rect destTrimmedRect = destScissoredRect;

+

+    // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of 

+    // the actual draw and read surfaces.

+    if(sourceTrimmedRect.x0 < 0)

+    {

+        int xDiff = 0 - sourceTrimmedRect.x0;

+        sourceTrimmedRect.x0 = 0;

+        destTrimmedRect.x0 += xDiff;

+    }

+

+    if(sourceTrimmedRect.x1 > readBufferWidth)

+    {

+        int xDiff = sourceTrimmedRect.x1 - readBufferWidth;

+        sourceTrimmedRect.x1 = readBufferWidth;

+        destTrimmedRect.x1 -= xDiff;

+    }

+

+    if(sourceTrimmedRect.y0 < 0)

+    {

+        int yDiff = 0 - sourceTrimmedRect.y0;

+        sourceTrimmedRect.y0 = 0;

+        destTrimmedRect.y0 += yDiff;

+    }

+

+    if(sourceTrimmedRect.y1 > readBufferHeight)

+    {

+        int yDiff = sourceTrimmedRect.y1 - readBufferHeight;

+        sourceTrimmedRect.y1 = readBufferHeight;

+        destTrimmedRect.y1 -= yDiff;

+    }

+

+    if(destTrimmedRect.x0 < 0)

+    {

+        int xDiff = 0 - destTrimmedRect.x0;

+        destTrimmedRect.x0 = 0;

+        sourceTrimmedRect.x0 += xDiff;

+    }

+

+    if(destTrimmedRect.x1 > drawBufferWidth)

+    {

+        int xDiff = destTrimmedRect.x1 - drawBufferWidth;

+        destTrimmedRect.x1 = drawBufferWidth;

+        sourceTrimmedRect.x1 -= xDiff;

+    }

+

+    if(destTrimmedRect.y0 < 0)

+    {

+        int yDiff = 0 - destTrimmedRect.y0;

+        destTrimmedRect.y0 = 0;

+        sourceTrimmedRect.y0 += yDiff;

+    }

+

+    if(destTrimmedRect.y1 > drawBufferHeight)

+    {

+        int yDiff = destTrimmedRect.y1 - drawBufferHeight;

+        destTrimmedRect.y1 = drawBufferHeight;

+        sourceTrimmedRect.y1 -= yDiff;

+    }

+

+    bool partialBufferCopy = false;

+

+    if(sourceTrimmedRect.y1 - sourceTrimmedRect.y0 < readBufferHeight ||

+       sourceTrimmedRect.x1 - sourceTrimmedRect.x0 < readBufferWidth || 

+       destTrimmedRect.y1 - destTrimmedRect.y0 < drawBufferHeight ||

+       destTrimmedRect.x1 - destTrimmedRect.x0 < drawBufferWidth ||

+       sourceTrimmedRect.y0 != 0 || destTrimmedRect.y0 != 0 || sourceTrimmedRect.x0 != 0 || destTrimmedRect.x0 != 0)

+    {

+        partialBufferCopy = true;

+    }

+

+	bool blitRenderTarget = false;

+    bool blitDepthStencil = false;

+

+    if(mask & GL_COLOR_BUFFER_BIT)

+    {

+        const bool validReadType = readFramebuffer->getColorbufferType() == GL_TEXTURE_2D ||

+                                   readFramebuffer->getColorbufferType() == GL_RENDERBUFFER;

+        const bool validDrawType = drawFramebuffer->getColorbufferType() == GL_TEXTURE_2D ||

+                                   drawFramebuffer->getColorbufferType() == GL_RENDERBUFFER;

+        if(!validReadType || !validDrawType ||

+           readFramebuffer->getColorbuffer()->getInternalFormat() != drawFramebuffer->getColorbuffer()->getInternalFormat())

+        {

+            ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");

+            return error(GL_INVALID_OPERATION);

+        }

+        

+        if(partialBufferCopy && readBufferSamples > 1)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        blitRenderTarget = true;

+    }

+

+    if(mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))

+    {

+        Renderbuffer *readDSBuffer = NULL;

+        Renderbuffer *drawDSBuffer = NULL;

+

+        // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have

+        // both a depth and stencil buffer, it will be the same buffer.

+

+        if(mask & GL_DEPTH_BUFFER_BIT)

+        {

+            if(readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer())

+            {

+                if(readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() ||

+                   readFramebuffer->getDepthbuffer()->getInternalFormat() != drawFramebuffer->getDepthbuffer()->getInternalFormat())

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                blitDepthStencil = true;

+                readDSBuffer = readFramebuffer->getDepthbuffer();

+                drawDSBuffer = drawFramebuffer->getDepthbuffer();

+            }

+        }

+

+        if(mask & GL_STENCIL_BUFFER_BIT)

+        {

+            if(readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer())

+            {

+                if(readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() ||

+                   readFramebuffer->getStencilbuffer()->getInternalFormat() != drawFramebuffer->getStencilbuffer()->getInternalFormat())

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                blitDepthStencil = true;

+                readDSBuffer = readFramebuffer->getStencilbuffer();

+                drawDSBuffer = drawFramebuffer->getStencilbuffer();

+            }

+        }

+

+        if(partialBufferCopy)

+        {

+            ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");

+            return error(GL_INVALID_OPERATION);   // Only whole-buffer copies are permitted

+        }

+

+        if((drawDSBuffer && drawDSBuffer->getSamples() > 1) || 

+           (readDSBuffer && readDSBuffer->getSamples() > 1))

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+    }

+

+    if(blitRenderTarget || blitDepthStencil)

+    {

+        if(blitRenderTarget)

+        {

+            Image *readRenderTarget = readFramebuffer->getRenderTarget();

+            Image *drawRenderTarget = drawFramebuffer->getRenderTarget();

+ 

+            bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, false);

+

+            readRenderTarget->release();

+            drawRenderTarget->release();

+

+            if(!success)

+            {

+                ERR("BlitFramebufferANGLE failed.");

+                return;

+            }

+        }

+

+        if(blitDepthStencil)

+        {

+            bool success = device->stretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, false);

+

+            if(!success)

+            {

+                ERR("BlitFramebufferANGLE failed.");

+                return;

+            }

+        }

+    }

+}

+

+}

+

+// Exported functions for use by EGL

+extern "C"

+{

+	gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext)

+	{

+		return new gl::Context(config, shareContext);

+	}

+

+	void glDestroyContext(gl::Context *context)

+	{

+		delete context;

+

+		if(context == gl::getContext())

+		{

+			gl::makeCurrent(NULL, NULL, NULL);

+		}

+	}

+

+	void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)

+	{

+		gl::makeCurrent(context, display, surface);

+	}

+

+	gl::Context *glGetCurrentContext()

+	{

+		return gl::getContext();

+	}

+}

diff --git a/src/GLES2/libGLES_CM/Context.h b/src/GLES2/libGLES_CM/Context.h
new file mode 100644
index 0000000..cbeb2bd
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Context.h
@@ -0,0 +1,488 @@
+// 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.

+//

+

+// Context.h: Defines the Context class, managing all GL state and performing

+// rendering operations. It is the GLES2 specific implementation of EGLContext.

+

+#ifndef LIBGLESV2_CONTEXT_H_

+#define LIBGLESV2_CONTEXT_H_

+

+#include "ResourceManager.h"

+#include "HandleAllocator.h"

+#include "RefCountObject.h"

+#include "Image.hpp"

+#include "Renderer/Sampler.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+#include <GLES2/gl2ext.h>

+#define EGLAPI

+#include <EGL/egl.h>

+

+#include <map>

+#include <string>

+

+namespace egl

+{

+class Display;

+class Surface;

+class Config;

+}

+

+namespace gl

+{

+struct TranslatedAttribute;

+struct TranslatedIndexData;

+

+class Buffer;

+class Shader;

+class Program;

+class Texture;

+class Texture2D;

+class TextureCubeMap;

+class TextureExternal;

+class Framebuffer;

+class Renderbuffer;

+class RenderbufferStorage;

+class Colorbuffer;

+class Depthbuffer;

+class StreamingIndexBuffer;

+class Stencilbuffer;

+class DepthStencilbuffer;

+class VertexDataManager;

+class IndexDataManager;

+class Fence;

+class Query;

+

+enum

+{

+    MAX_VERTEX_ATTRIBS = 16,

+	MAX_UNIFORM_VECTORS = 256,   // Device limit

+    MAX_VERTEX_UNIFORM_VECTORS = 256 - 3,   // Reserve space for gl_DepthRange

+    MAX_VARYING_VECTORS = 10,

+    MAX_TEXTURE_IMAGE_UNITS = 16,

+    MAX_VERTEX_TEXTURE_IMAGE_UNITS = 4,

+    MAX_COMBINED_TEXTURE_IMAGE_UNITS = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS,

+    MAX_FRAGMENT_UNIFORM_VECTORS = 224 - 3,    // Reserve space for gl_DepthRange

+    MAX_DRAW_BUFFERS = 1,

+

+    IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,

+    IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5

+};

+

+enum QueryType

+{

+    QUERY_ANY_SAMPLES_PASSED,

+    QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE,

+

+    QUERY_TYPE_COUNT

+};

+

+const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f;

+const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f;

+const float ALIASED_POINT_SIZE_RANGE_MIN = 0.125f;

+const float ALIASED_POINT_SIZE_RANGE_MAX = 8192.0f;

+const float MAX_TEXTURE_MAX_ANISOTROPY = 16.0f;

+

+struct Color

+{

+    float red;

+    float green;

+    float blue;

+    float alpha;

+};

+

+// Helper structure describing a single vertex attribute

+class VertexAttribute

+{

+  public:

+    VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false)

+    {

+        mCurrentValue[0] = 0.0f;

+        mCurrentValue[1] = 0.0f;

+        mCurrentValue[2] = 0.0f;

+        mCurrentValue[3] = 1.0f;

+    }

+

+    int typeSize() const

+    {

+        switch (mType)

+        {

+        case GL_BYTE:           return mSize * sizeof(GLbyte);

+        case GL_UNSIGNED_BYTE:  return mSize * sizeof(GLubyte);

+        case GL_SHORT:          return mSize * sizeof(GLshort);

+        case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort);

+        case GL_FIXED:          return mSize * sizeof(GLfixed);

+        case GL_FLOAT:          return mSize * sizeof(GLfloat);

+        default: UNREACHABLE(); return mSize * sizeof(GLfloat);

+        }

+    }

+

+    GLsizei stride() const

+    {

+        return mStride ? mStride : typeSize();

+    }

+

+    // From glVertexAttribPointer

+    GLenum mType;

+    GLint mSize;

+    bool mNormalized;

+    GLsizei mStride;   // 0 means natural stride

+

+    union

+    {

+        const void *mPointer;

+        intptr_t mOffset;

+    };

+

+    BindingPointer<Buffer> mBoundBuffer;   // Captured when glVertexAttribPointer is called.

+

+    bool mArrayEnabled;   // From glEnable/DisableVertexAttribArray

+    float mCurrentValue[4];   // From glVertexAttrib

+};

+

+typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS];

+

+// Helper structure to store all raw state

+struct State

+{

+    Color colorClearValue;

+    GLclampf depthClearValue;

+    int stencilClearValue;

+

+    bool cullFace;

+    GLenum cullMode;

+    GLenum frontFace;

+    bool depthTest;

+    GLenum depthFunc;

+    bool blend;

+    GLenum sourceBlendRGB;

+    GLenum destBlendRGB;

+    GLenum sourceBlendAlpha;

+    GLenum destBlendAlpha;

+    GLenum blendEquationRGB;

+    GLenum blendEquationAlpha;

+    Color blendColor;

+    bool stencilTest;

+    GLenum stencilFunc;

+    GLint stencilRef;

+    GLuint stencilMask;

+    GLenum stencilFail;

+    GLenum stencilPassDepthFail;

+    GLenum stencilPassDepthPass;

+    GLuint stencilWritemask;

+    GLenum stencilBackFunc;

+    GLint stencilBackRef;

+    GLuint stencilBackMask;

+    GLenum stencilBackFail;

+    GLenum stencilBackPassDepthFail;

+    GLenum stencilBackPassDepthPass;

+    GLuint stencilBackWritemask;

+    bool polygonOffsetFill;

+    GLfloat polygonOffsetFactor;

+    GLfloat polygonOffsetUnits;

+    bool sampleAlphaToCoverage;

+    bool sampleCoverage;

+    GLclampf sampleCoverageValue;

+    bool sampleCoverageInvert;

+    bool scissorTest;

+    bool dither;

+

+    GLfloat lineWidth;

+

+    GLenum generateMipmapHint;

+    GLenum fragmentShaderDerivativeHint;

+

+    GLint viewportX;

+    GLint viewportY;

+    GLsizei viewportWidth;

+    GLsizei viewportHeight;

+    float zNear;

+    float zFar;

+

+    GLint scissorX;

+    GLint scissorY;

+    GLsizei scissorWidth;

+    GLsizei scissorHeight;

+

+    bool colorMaskRed;

+    bool colorMaskGreen;

+    bool colorMaskBlue;

+    bool colorMaskAlpha;

+    bool depthMask;

+

+    unsigned int activeSampler;   // Active texture unit selector - GL_TEXTURE0

+    BindingPointer<Buffer> arrayBuffer;

+    BindingPointer<Buffer> elementArrayBuffer;

+    GLuint readFramebuffer;

+    GLuint drawFramebuffer;

+    BindingPointer<Renderbuffer> renderbuffer;

+    GLuint currentProgram;

+

+    VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS];

+    BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS];

+	BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT];

+

+    GLint unpackAlignment;

+    GLint packAlignment;

+};

+

+class Context

+{

+  public:

+    Context(const egl::Config *config, const Context *shareContext);

+

+    virtual ~Context();

+

+    void makeCurrent(egl::Display *display, egl::Surface *surface);

+

+    void markAllStateDirty();

+

+    // State manipulation

+    void setClearColor(float red, float green, float blue, float alpha);

+    void setClearDepth(float depth);

+    void setClearStencil(int stencil);

+

+    void setCullFace(bool enabled);

+    bool isCullFaceEnabled() const;

+    void setCullMode(GLenum mode);

+    void setFrontFace(GLenum front);

+

+    void setDepthTest(bool enabled);

+    bool isDepthTestEnabled() const;

+    void setDepthFunc(GLenum depthFunc);

+    void setDepthRange(float zNear, float zFar);

+    

+    void setBlend(bool enabled);

+    bool isBlendEnabled() const;

+    void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha);

+    void setBlendColor(float red, float green, float blue, float alpha);

+    void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation);

+

+    void setStencilTest(bool enabled);

+    bool isStencilTestEnabled() const;

+    void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask);

+    void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask);

+    void setStencilWritemask(GLuint stencilWritemask);

+    void setStencilBackWritemask(GLuint stencilBackWritemask);

+    void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass);

+    void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass);

+

+    void setPolygonOffsetFill(bool enabled);

+    bool isPolygonOffsetFillEnabled() const;

+    void setPolygonOffsetParams(GLfloat factor, GLfloat units);

+

+    void setSampleAlphaToCoverage(bool enabled);

+    bool isSampleAlphaToCoverageEnabled() const;

+    void setSampleCoverage(bool enabled);

+    bool isSampleCoverageEnabled() const;

+    void setSampleCoverageParams(GLclampf value, bool invert);

+

+    void setDither(bool enabled);

+    bool isDitherEnabled() const;

+

+    void setLineWidth(GLfloat width);

+

+    void setGenerateMipmapHint(GLenum hint);

+    void setFragmentShaderDerivativeHint(GLenum hint);

+

+    void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height);

+

+	void setScissorTest(bool enabled);

+    bool isScissorTestEnabled() const;

+    void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height);

+

+    void setColorMask(bool red, bool green, bool blue, bool alpha);

+    void setDepthMask(bool mask);

+

+    void setActiveSampler(unsigned int active);

+

+    GLuint getReadFramebufferHandle() const;

+    GLuint getDrawFramebufferHandle() const;

+    GLuint getRenderbufferHandle() const;

+

+	GLuint getActiveQuery(GLenum target) const;

+

+    GLuint getArrayBufferHandle() const;

+

+    void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);

+    const VertexAttribute &getVertexAttribState(unsigned int attribNum);

+    void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,

+                              bool normalized, GLsizei stride, const void *pointer);

+    const void *getVertexAttribPointer(unsigned int attribNum) const;

+

+    const VertexAttributeArray &getVertexAttributes();

+

+    void setUnpackAlignment(GLint alignment);

+    GLint getUnpackAlignment() const;

+

+    void setPackAlignment(GLint alignment);

+    GLint getPackAlignment() const;

+

+    // These create  and destroy methods are merely pass-throughs to 

+    // ResourceManager, which owns these object types

+    GLuint createBuffer();

+    GLuint createShader(GLenum type);

+    GLuint createProgram();

+    GLuint createTexture();

+    GLuint createRenderbuffer();

+

+    void deleteBuffer(GLuint buffer);

+    void deleteShader(GLuint shader);

+    void deleteProgram(GLuint program);

+    void deleteTexture(GLuint texture);

+    void deleteRenderbuffer(GLuint renderbuffer);

+

+    // Framebuffers are owned by the Context, so these methods do not pass through

+    GLuint createFramebuffer();

+    void deleteFramebuffer(GLuint framebuffer);

+

+    // Fences are owned by the Context

+    GLuint createFence();

+    void deleteFence(GLuint fence);

+

+	// Queries are owned by the Context

+    GLuint createQuery();

+    void deleteQuery(GLuint query);

+

+    void bindArrayBuffer(GLuint buffer);

+    void bindElementArrayBuffer(GLuint buffer);

+    void bindTexture2D(GLuint texture);

+    void bindTextureCubeMap(GLuint texture);

+    void bindTextureExternal(GLuint texture);

+    void bindReadFramebuffer(GLuint framebuffer);

+    void bindDrawFramebuffer(GLuint framebuffer);

+    void bindRenderbuffer(GLuint renderbuffer);

+    void useProgram(GLuint program);

+

+	void beginQuery(GLenum target, GLuint query);

+    void endQuery(GLenum target);

+

+    void setFramebufferZero(Framebuffer *framebuffer);

+

+    void setRenderbufferStorage(RenderbufferStorage *renderbuffer);

+

+    void setVertexAttrib(GLuint index, const GLfloat *values);

+

+    Buffer *getBuffer(GLuint handle);

+    Fence *getFence(GLuint handle);

+    Shader *getShader(GLuint handle);

+    Program *getProgram(GLuint handle);

+    virtual Texture *getTexture(GLuint handle);

+    Framebuffer *getFramebuffer(GLuint handle);

+    virtual Renderbuffer *getRenderbuffer(GLuint handle);

+	Query *getQuery(GLuint handle, bool create, GLenum type);

+

+    Buffer *getArrayBuffer();

+    Buffer *getElementArrayBuffer();

+    Program *getCurrentProgram();

+    Texture2D *getTexture2D();

+    TextureCubeMap *getTextureCubeMap();

+    TextureExternal *getTextureExternal();

+    Texture *getSamplerTexture(unsigned int sampler, TextureType type);

+    Framebuffer *getReadFramebuffer();

+    Framebuffer *getDrawFramebuffer();

+

+    bool getFloatv(GLenum pname, GLfloat *params);

+    bool getIntegerv(GLenum pname, GLint *params);

+    bool getBooleanv(GLenum pname, GLboolean *params);

+

+    bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);

+

+    void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels);

+    void clear(GLbitfield mask);

+    void drawArrays(GLenum mode, GLint first, GLsizei count);

+    void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);

+    void finish();

+    void flush();

+

+    void recordInvalidEnum();

+    void recordInvalidValue();

+    void recordInvalidOperation();

+    void recordOutOfMemory();

+    void recordInvalidFramebufferOperation();

+

+    GLenum getError();

+

+    static int getSupportedMultiSampleDepth(sw::Format format, int requested);

+    

+    void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 

+                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,

+                         GLbitfield mask);

+

+  private:

+    bool applyRenderTarget();

+    void applyState(GLenum drawMode);

+    GLenum applyVertexBuffer(GLint base, GLint first, GLsizei count);

+    GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);

+    void applyShaders();

+    void applyTextures();

+    void applyTextures(sw::SamplerType type);

+	void applyTexture(sw::SamplerType type, int sampler, Texture *texture);

+

+    void detachBuffer(GLuint buffer);

+    void detachTexture(GLuint texture);

+    void detachFramebuffer(GLuint framebuffer);

+    void detachRenderbuffer(GLuint renderbuffer);

+

+    bool cullSkipsDraw(GLenum drawMode);

+    bool isTriangleMode(GLenum drawMode);

+

+    const egl::Config *const mConfig;

+

+    State mState;

+

+    BindingPointer<Texture2D> mTexture2DZero;

+    BindingPointer<TextureCubeMap> mTextureCubeMapZero;

+    BindingPointer<TextureExternal> mTextureExternalZero;

+

+    typedef std::map<GLint, Framebuffer*> FramebufferMap;

+    FramebufferMap mFramebufferMap;

+    HandleAllocator mFramebufferHandleAllocator;

+

+    typedef std::map<GLint, Fence*> FenceMap;

+    FenceMap mFenceMap;

+    HandleAllocator mFenceHandleAllocator;

+

+	typedef std::map<GLint, Query*> QueryMap;

+    QueryMap mQueryMap;

+    HandleAllocator mQueryHandleAllocator;

+

+    VertexDataManager *mVertexDataManager;

+    IndexDataManager *mIndexDataManager;

+

+    // Recorded errors

+    bool mInvalidEnum;

+    bool mInvalidValue;

+    bool mInvalidOperation;

+    bool mOutOfMemory;

+    bool mInvalidFramebufferOperation;

+

+    bool mHasBeenCurrent;

+

+    unsigned int mAppliedProgramSerial;

+    

+    // state caching flags

+    bool mDepthStateDirty;

+    bool mMaskStateDirty;

+    bool mPixelPackingStateDirty;

+    bool mBlendStateDirty;

+    bool mStencilStateDirty;

+    bool mPolygonOffsetStateDirty;

+    bool mSampleStateDirty;

+    bool mFrontFaceDirty;

+    bool mDitherStateDirty;

+

+    ResourceManager *mResourceManager;

+};

+}

+

+#endif   // INCLUDE_CONTEXT_H_

diff --git a/src/GLES2/libGLES_CM/Device.cpp b/src/GLES2/libGLES_CM/Device.cpp
new file mode 100644
index 0000000..c2cc36a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Device.cpp
@@ -0,0 +1,801 @@
+// 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 "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 = false;

+

+namespace gl

+{

+	using namespace sw;

+

+	Device::Device(Context *context) : Renderer(context, true, true, true, true, true), context(context)

+	{

+		depthStencil = 0;

+		renderTarget = 0;

+

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

+		setAlphaCompare(ALPHA_ALWAYS);

+		setAlphaBlendEnable(false);

+		setFogEnable(false);

+		setSpecularEnable(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);

+		setPointSpriteEnable(false);

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

+

+		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->release();

+			depthStencil = 0;

+		}

+		

+		if(renderTarget)

+		{

+			renderTarget->release();

+			renderTarget = 0;

+		}

+

+		delete context;

+	}

+

+	void Device::clearColor(unsigned int color, unsigned int rgbaMask)

+	{

+		TRACE("unsigned long color = 0x%0.8X", color);

+

+		if(!renderTarget)

+		{

+			return;

+		}

+

+		int x0 = 0;

+		int y0 = 0;

+		int width = renderTarget->getExternalWidth();

+		int height = renderTarget->getExternalHeight();

+

+		if(scissorEnable)   // Clamp against scissor rectangle

+		{

+			if(x0 < scissorRect.x0) x0 = scissorRect.x0;

+			if(y0 < scissorRect.y0) y0 = scissorRect.y0;

+			if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;

+			if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;

+		}

+

+		renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+	}

+

+	void Device::clearDepth(float z)

+	{

+		TRACE("float z = %f", z);

+

+		if(!depthStencil)

+		{

+			return;

+		}

+

+		if(z > 1) z = 1;

+		if(z < 0) z = 0;

+

+		int x0 = 0;

+		int y0 = 0;

+		int width = depthStencil->getExternalWidth();

+		int height = depthStencil->getExternalHeight();

+

+		if(scissorEnable)   // Clamp against scissor rectangle

+		{

+			if(x0 < scissorRect.x0) x0 = scissorRect.x0;

+			if(y0 < scissorRect.y0) y0 = scissorRect.y0;

+			if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;

+			if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;

+		}

+			

+		depthStencil->clearDepthBuffer(z, x0, y0, width, height);

+	}

+

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

+	{

+		TRACE("unsigned long stencil = %d", stencil);

+

+		if(!depthStencil)

+		{

+			return;

+		}

+

+		int x0 = 0;

+		int y0 = 0;

+		int width = depthStencil->getExternalWidth();

+		int height = depthStencil->getExternalHeight();

+

+		if(scissorEnable)   // Clamp against scissor rectangle

+		{

+			if(x0 < scissorRect.x0) x0 = scissorRect.x0;

+			if(y0 < scissorRect.y0) y0 = scissorRect.y0;

+			if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;

+			if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;

+		}

+

+		depthStencil->clearStencilBuffer(stencil, mask, x0, y0, 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_DF24S8:

+		case FORMAT_DF16S8:

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

+		}

+

+		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, true);

+

+		if(!surface)

+		{

+			ERR("Out of memory");

+			return 0;

+		}

+		

+		return surface;

+	}

+

+	void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)

+	{

+		TRACE("");

+

+		if(!bindResources() || !primitiveCount)

+		{

+			return;

+		}

+

+		DrawType drawType;

+

+		if(indexSize == 4)

+		{

+			switch(type)

+			{

+			case DRAW_POINTLIST:     drawType = sw::DRAW_INDEXEDPOINTLIST32;     break;

+			case DRAW_LINELIST:      drawType = sw::DRAW_INDEXEDLINELIST32;      break;

+			case DRAW_LINESTRIP:     drawType = sw::DRAW_INDEXEDLINESTRIP32;     break;

+			case DRAW_LINELOOP:      drawType = sw::DRAW_INDEXEDLINELOOP32;      break;

+			case DRAW_TRIANGLELIST:  drawType = sw::DRAW_INDEXEDTRIANGLELIST32;  break;

+			case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break;

+			case DRAW_TRIANGLEFAN:   drawType = sw::DRAW_INDEXEDTRIANGLEFAN32;	  break;

+			default: UNREACHABLE();

+			}

+		}

+		else if(indexSize == 2)

+		{

+			switch(type)

+			{

+			case DRAW_POINTLIST:     drawType = sw::DRAW_INDEXEDPOINTLIST16;     break;

+			case DRAW_LINELIST:      drawType = sw::DRAW_INDEXEDLINELIST16;      break;

+			case DRAW_LINESTRIP:     drawType = sw::DRAW_INDEXEDLINESTRIP16;     break;

+			case DRAW_LINELOOP:      drawType = sw::DRAW_INDEXEDLINELOOP16;      break;

+			case DRAW_TRIANGLELIST:  drawType = sw::DRAW_INDEXEDTRIANGLELIST16;  break;

+			case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break;

+			case DRAW_TRIANGLEFAN:   drawType = sw::DRAW_INDEXEDTRIANGLEFAN16;   break;

+			default: UNREACHABLE();

+			}

+		}

+		else if(indexSize == 1)

+		{

+			switch(type)

+			{

+			case DRAW_POINTLIST:     drawType = sw::DRAW_INDEXEDPOINTLIST8;     break;

+			case DRAW_LINELIST:      drawType = sw::DRAW_INDEXEDLINELIST8;      break;

+			case DRAW_LINESTRIP:     drawType = sw::DRAW_INDEXEDLINESTRIP8;     break;

+			case DRAW_LINELOOP:      drawType = sw::DRAW_INDEXEDLINELOOP8;      break;

+			case DRAW_TRIANGLELIST:  drawType = sw::DRAW_INDEXEDTRIANGLELIST8;  break;

+			case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP8; break;

+			case DRAW_TRIANGLEFAN:   drawType = sw::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);

+		

+		DrawType drawType;

+

+		switch(primitiveType)

+		{

+		case DRAW_POINTLIST:     drawType = sw::DRAW_POINTLIST;     break;

+		case DRAW_LINELIST:      drawType = sw::DRAW_LINELIST;      break;

+		case DRAW_LINESTRIP:     drawType = sw::DRAW_LINESTRIP;     break;

+		case DRAW_LINELOOP:      drawType = sw::DRAW_LINELOOP;      break;

+		case DRAW_TRIANGLELIST:  drawType = sw::DRAW_TRIANGLELIST;  break;

+		case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break;

+		case DRAW_TRIANGLEFAN:   drawType = sw::DRAW_TRIANGLEFAN;   break;

+		default: UNREACHABLE();

+		}

+

+		draw(drawType, 0, primitiveCount);

+	}

+

+	void Device::setDepthStencilSurface(Image *depthStencil)

+	{

+		TRACE("Image *newDepthStencil = 0x%0.8p", depthStencil);

+

+		if(this->depthStencil == depthStencil)

+		{

+			return;

+		}

+

+		if(depthStencil)

+		{

+			depthStencil->addRef();

+		}

+

+		if(this->depthStencil)

+		{

+			this->depthStencil->release();

+		}

+

+		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 *renderTarget)

+	{

+		TRACE("Image *newRenderTarget = 0x%0.8p", renderTarget);

+

+		if(renderTarget)

+		{

+			renderTarget->addRef();

+		}

+

+		if(this->renderTarget)

+		{

+			this->renderTarget->release();

+		}

+

+		this->renderTarget = renderTarget;

+

+		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 *source, const sw::Rect *sourceRect, Image *dest, 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", source, sourceRect, dest, destRect, filter);

+

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

+		{

+			ERR("Invalid parameters");

+			return false;

+		}

+		

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

+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, 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 * 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

+		}

+

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

+		{

+			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->getExternalWidth());

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

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

+			}

+

+			if(depthStencil)

+			{

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

+				scissor.x1 = min(scissor.x1, depthStencil->getExternalWidth());

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

+				scissor.y1 = min(scissor.y1, depthStencil->getExternalHeight());

+			}

+

+			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, Image *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();

+	}

+}

+

+// Exported functions for use by EGL

+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
diff --git a/src/GLES2/libGLES_CM/Device.hpp b/src/GLES2/libGLES_CM/Device.hpp
new file mode 100644
index 0000000..4e0337d
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Device.hpp
@@ -0,0 +1,103 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+#ifndef gl_Device_hpp

+#define gl_Device_hpp

+

+#include "Renderer/Renderer.hpp"

+

+namespace gl

+{

+	class Texture;

+}

+

+namespace gl

+{

+	class Image;

+

+	enum PrimitiveType

+	{

+		DRAW_POINTLIST,

+		DRAW_LINELIST,

+		DRAW_LINESTRIP,

+		DRAW_LINELOOP,

+		DRAW_TRIANGLELIST,

+		DRAW_TRIANGLESTRIP,

+		DRAW_TRIANGLEFAN

+	};

+

+	struct Viewport

+	{

+		int x0;

+		int y0;

+		unsigned int width;

+		unsigned int height;

+		float minZ;

+		float maxZ;

+	};

+

+	class Device : public sw::Renderer

+	{

+	public:

+		explicit Device(sw::Context *context);

+

+		virtual ~Device();

+

+		virtual void clearColor(unsigned int color, unsigned int rgbaMask);

+		virtual void clearDepth(float z);

+		virtual void clearStencil(unsigned int stencil, unsigned int mask);

+		virtual Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);

+		virtual Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);

+		virtual void drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize);

+		virtual void drawPrimitive(PrimitiveType primitiveType, unsigned int primiveCount);

+		virtual void setDepthStencilSurface(Image *newDepthStencil);

+		virtual void setPixelShader(sw::PixelShader *shader);

+		virtual void setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);

+		virtual void setScissorEnable(bool enable);

+		virtual void setRenderTarget(Image *renderTarget);

+		virtual void setScissorRect(const sw::Rect &rect);

+		virtual void setVertexShader(sw::VertexShader *shader);

+		virtual void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);

+		virtual void setViewport(const Viewport &viewport);

+

+		virtual bool stretchRect(Image *sourceSurface, const sw::Rect *sourceRect, Image *destSurface, const sw::Rect *destRect, bool filter);

+		virtual void finish();

+

+	private:

+		sw::Context *const context;

+

+		bool bindResources();

+		void bindShaderConstants();

+		bool bindViewport();   // Also adjusts for scissoring

+

+		bool validRectangle(const sw::Rect *rect, Image *surface);

+

+		Viewport viewport;

+		sw::Rect scissorRect;

+		bool scissorEnable;

+

+		sw::PixelShader *pixelShader;

+		sw::VertexShader *vertexShader;

+

+		bool pixelShaderDirty;

+		unsigned int pixelShaderConstantsFDirty;

+		bool vertexShaderDirty;

+		unsigned int vertexShaderConstantsFDirty;

+

+		float pixelShaderConstantF[224][4];

+		float vertexShaderConstantF[256][4];

+

+		Image *renderTarget;

+		Image *depthStencil;

+	};

+}

+

+#endif   // gl_Device_hpp

diff --git a/src/GLES2/libGLES_CM/Fence.cpp b/src/GLES2/libGLES_CM/Fence.cpp
new file mode 100644
index 0000000..8221075
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Fence.cpp
@@ -0,0 +1,108 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// Fence.cpp: Implements the Fence class, which supports the GL_NV_fence extension.

+

+#include "Fence.h"

+

+#include "main.h"

+#include "Common/Thread.hpp"

+

+namespace gl

+{

+

+Fence::Fence()

+{ 

+    mQuery = false;

+    mCondition = GL_NONE;

+    mStatus = GL_FALSE;

+}

+

+Fence::~Fence()

+{

+    mQuery = false;

+}

+

+GLboolean Fence::isFence()

+{

+    // GL_NV_fence spec:

+    // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.

+    return mQuery;

+}

+

+void Fence::setFence(GLenum condition)

+{

+    mQuery = true;

+    mCondition = condition;

+    mStatus = GL_FALSE;

+}

+

+GLboolean Fence::testFence()

+{

+    if(!mQuery)

+    {

+        return error(GL_INVALID_OPERATION, GL_TRUE);

+    }

+

+	UNIMPLEMENTED();

+    mStatus = GL_TRUE;

+

+    return mStatus;

+}

+

+void Fence::finishFence()

+{

+    if(!mQuery)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    while(!testFence())

+    {

+        sw::Thread::yield();

+    }

+}

+

+void Fence::getFenceiv(GLenum pname, GLint *params)

+{

+    if(!mQuery)

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    switch (pname)

+    {

+    case GL_FENCE_STATUS_NV:

+		{

+			// GL_NV_fence spec:

+			// Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV

+			// or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.

+			if(mStatus)

+			{

+				params[0] = GL_TRUE;

+				return;

+			}

+            

+			mStatus = testFence();

+

+			params[0] = mStatus;            

+			break;

+		}

+    case GL_FENCE_CONDITION_NV:

+        params[0] = mCondition;

+        break;

+    default:

+        return error(GL_INVALID_ENUM);

+        break;

+    }

+}

+

+}

diff --git a/src/GLES2/libGLES_CM/Fence.h b/src/GLES2/libGLES_CM/Fence.h
new file mode 100644
index 0000000..bd6d9ac
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Fence.h
@@ -0,0 +1,43 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// Fence.h: Defines the Fence class, which supports the GL_NV_fence extension.

+

+#ifndef LIBGLESV2_FENCE_H_

+#define LIBGLESV2_FENCE_H_

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+

+class Fence

+{

+  public:

+    Fence();

+    virtual ~Fence();

+

+    GLboolean isFence();

+    void setFence(GLenum condition);

+    GLboolean testFence();

+    void finishFence();

+    void getFenceiv(GLenum pname, GLint *params);

+

+  private:

+    bool mQuery;

+    GLenum mCondition;

+    GLboolean mStatus;

+};

+

+}

+

+#endif   // LIBGLESV2_FENCE_H_

diff --git a/src/GLES2/libGLES_CM/Framebuffer.cpp b/src/GLES2/libGLES_CM/Framebuffer.cpp
new file mode 100644
index 0000000..8ba7d9e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Framebuffer.cpp
@@ -0,0 +1,423 @@
+// 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.
+//
+
+// Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#include "Framebuffer.h"
+
+#include "main.h"
+#include "Renderbuffer.h"
+#include "Texture.h"
+#include "utilities.h"
+
+namespace gl
+{
+
+Framebuffer::Framebuffer()
+{
+	mColorbufferType = GL_NONE;
+	mDepthbufferType = GL_NONE;
+	mStencilbufferType = GL_NONE;
+}
+
+Framebuffer::~Framebuffer()
+{
+	mColorbufferPointer.set(NULL);
+	mDepthbufferPointer.set(NULL);
+	mStencilbufferPointer.set(NULL);
+}
+
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
+{
+	Context *context = getContext();
+	Renderbuffer *buffer = NULL;
+
+	if(type == GL_NONE)
+	{
+		buffer = NULL;
+	}
+	else if(type == GL_RENDERBUFFER)
+	{
+		buffer = context->getRenderbuffer(handle);
+	}
+	else if(IsTextureTarget(type))
+	{
+		buffer = context->getTexture(handle)->getRenderbuffer(type);
+	}
+	else
+	{
+		UNREACHABLE();
+	}
+
+	return buffer;
+}
+
+void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
+{
+	mColorbufferType = (colorbuffer != 0) ? type : GL_NONE;
+	mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
+}
+
+void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
+{
+	mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
+	mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
+}
+
+void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
+{
+	mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
+	mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
+}
+
+void Framebuffer::detachTexture(GLuint texture)
+{
+	if(mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
+	{
+		mColorbufferType = GL_NONE;
+		mColorbufferPointer.set(NULL);
+	}
+
+	if(mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
+	{
+		mDepthbufferType = GL_NONE;
+		mDepthbufferPointer.set(NULL);
+	}
+
+	if(mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
+	{
+		mStencilbufferType = GL_NONE;
+		mStencilbufferPointer.set(NULL);
+	}
+}
+
+void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
+{
+	if(mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
+	{
+		mColorbufferType = GL_NONE;
+		mColorbufferPointer.set(NULL);
+	}
+
+	if(mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
+	{
+		mDepthbufferType = GL_NONE;
+		mDepthbufferPointer.set(NULL);
+	}
+
+	if(mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
+	{
+		mStencilbufferType = GL_NONE;
+		mStencilbufferPointer.set(NULL);
+	}
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+Image *Framebuffer::getRenderTarget()
+{
+	Renderbuffer *colorbuffer = mColorbufferPointer.get();
+
+	if(colorbuffer)
+	{
+		return colorbuffer->getRenderTarget();
+	}
+
+	return NULL;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+Image *Framebuffer::getDepthStencil()
+{
+	Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
+	
+	if(!depthstencilbuffer)
+	{
+		depthstencilbuffer = mStencilbufferPointer.get();
+	}
+
+	if(depthstencilbuffer)
+	{
+		return depthstencilbuffer->getRenderTarget();
+	}
+
+	return NULL;
+}
+
+Renderbuffer *Framebuffer::getColorbuffer()
+{
+	return mColorbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getDepthbuffer()
+{
+	return mDepthbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getStencilbuffer()
+{
+	return mStencilbufferPointer.get();
+}
+
+GLenum Framebuffer::getColorbufferType()
+{
+	return mColorbufferType;
+}
+
+GLenum Framebuffer::getDepthbufferType()
+{
+	return mDepthbufferType;
+}
+
+GLenum Framebuffer::getStencilbufferType()
+{
+	return mStencilbufferType;
+}
+
+GLuint Framebuffer::getColorbufferHandle()
+{
+	return mColorbufferPointer.id();
+}
+
+GLuint Framebuffer::getDepthbufferHandle()
+{
+	return mDepthbufferPointer.id();
+}
+
+GLuint Framebuffer::getStencilbufferHandle()
+{
+	return mStencilbufferPointer.id();
+}
+
+bool Framebuffer::hasStencil()
+{
+	if(mStencilbufferType != GL_NONE)
+	{
+		Renderbuffer *stencilbufferObject = getStencilbuffer();
+
+		if(stencilbufferObject)
+		{
+			return stencilbufferObject->getStencilSize() > 0;
+		}
+	}
+
+	return false;
+}
+
+GLenum Framebuffer::completeness()
+{
+	int width;
+	int height;
+	int samples;
+
+	return completeness(width, height, samples);
+}
+
+GLenum Framebuffer::completeness(int &width, int &height, int &samples)
+{
+	width = -1;
+	height = -1;
+	samples = -1;
+
+	if(mColorbufferType != GL_NONE)
+	{
+		Renderbuffer *colorbuffer = getColorbuffer();
+
+		if(!colorbuffer)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(mColorbufferType == GL_RENDERBUFFER)
+		{
+			if(!gl::IsColorRenderable(colorbuffer->getFormat()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else if(IsTextureTarget(mColorbufferType))
+		{
+			GLenum format = colorbuffer->getFormat();
+
+			if(IsCompressed(format) ||
+			   format == GL_ALPHA ||
+			   format == GL_LUMINANCE ||
+			   format == GL_LUMINANCE_ALPHA)
+			{
+				return GL_FRAMEBUFFER_UNSUPPORTED;
+			}
+
+			if(gl::IsDepthTexture(format) || gl::IsStencilTexture(format))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else
+		{
+			UNREACHABLE();
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		width = colorbuffer->getWidth();
+		height = colorbuffer->getHeight();
+		samples = colorbuffer->getSamples();
+	}
+
+	Renderbuffer *depthbuffer = NULL;
+	Renderbuffer *stencilbuffer = NULL;
+
+	if(mDepthbufferType != GL_NONE)
+	{
+		depthbuffer = getDepthbuffer();
+
+		if(!depthbuffer)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(mDepthbufferType == GL_RENDERBUFFER)
+		{
+			if(!gl::IsDepthRenderable(depthbuffer->getFormat()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else if(IsTextureTarget(mDepthbufferType))
+		{
+			if(!gl::IsDepthTexture(depthbuffer->getFormat()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else
+		{
+			UNREACHABLE();
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(width == -1 || height == -1)
+		{
+			width = depthbuffer->getWidth();
+			height = depthbuffer->getHeight();
+			samples = depthbuffer->getSamples();
+		}
+		else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+		}
+		else if(samples != depthbuffer->getSamples())
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+		}
+	}
+
+	if(mStencilbufferType != GL_NONE)
+	{
+		stencilbuffer = getStencilbuffer();
+
+		if(!stencilbuffer)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(mStencilbufferType == GL_RENDERBUFFER)
+		{
+			if(!gl::IsStencilRenderable(stencilbuffer->getFormat()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else if(IsTextureTarget(mStencilbufferType))
+		{
+			GLenum internalformat = stencilbuffer->getFormat();
+
+			if(!gl::IsStencilTexture(internalformat))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+			}
+		}
+		else
+		{
+			UNREACHABLE();
+			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+		}
+
+		if(width == -1 || height == -1)
+		{
+			width = stencilbuffer->getWidth();
+			height = stencilbuffer->getHeight();
+			samples = stencilbuffer->getSamples();
+		}
+		else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+		}
+		else if(samples != stencilbuffer->getSamples())
+		{
+			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+		}
+	}
+
+	// If we have both a depth and stencil buffer, they must refer to the same object
+	// since we only support packed_depth_stencil and not separate depth and stencil
+	if(depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
+	{
+		return GL_FRAMEBUFFER_UNSUPPORTED;
+	}
+
+	// We need to have at least one attachment to be complete
+	if(width == -1 || height == -1)
+	{
+		return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+	}
+
+	return GL_FRAMEBUFFER_COMPLETE;
+}
+
+DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
+{
+	mColorbufferPointer.set(new Renderbuffer(0, colorbuffer));
+
+	Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
+	mDepthbufferPointer.set(depthStencilRenderbuffer);
+	mStencilbufferPointer.set(depthStencilRenderbuffer);
+
+	mColorbufferType = GL_RENDERBUFFER;
+	mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+	mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+}
+
+GLenum DefaultFramebuffer::completeness()
+{
+	// The default framebuffer should always be complete
+	ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
+
+	return GL_FRAMEBUFFER_COMPLETE;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Framebuffer.h b/src/GLES2/libGLES_CM/Framebuffer.h
new file mode 100644
index 0000000..c3e0f0b
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Framebuffer.h
@@ -0,0 +1,90 @@
+// 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.

+//

+

+// Framebuffer.h: Defines the Framebuffer class. Implements GL framebuffer

+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.

+

+#ifndef LIBGLESV2_FRAMEBUFFER_H_

+#define LIBGLESV2_FRAMEBUFFER_H_

+

+#include "RefCountObject.h"

+#include "Image.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+class Renderbuffer;

+class Colorbuffer;

+class Depthbuffer;

+class Stencilbuffer;

+class DepthStencilbuffer;

+

+class Framebuffer

+{

+public:

+    Framebuffer();

+

+    virtual ~Framebuffer();

+

+    void setColorbuffer(GLenum type, GLuint colorbuffer);

+    void setDepthbuffer(GLenum type, GLuint depthbuffer);

+    void setStencilbuffer(GLenum type, GLuint stencilbuffer);

+

+    void detachTexture(GLuint texture);

+    void detachRenderbuffer(GLuint renderbuffer);

+

+    Image *getRenderTarget();

+    Image *getDepthStencil();

+

+    Renderbuffer *getColorbuffer();

+    Renderbuffer *getDepthbuffer();

+    Renderbuffer *getStencilbuffer();

+

+    GLenum getColorbufferType();

+    GLenum getDepthbufferType();

+    GLenum getStencilbufferType();

+

+    GLuint getColorbufferHandle();

+    GLuint getDepthbufferHandle();

+    GLuint getStencilbufferHandle();

+

+    bool hasStencil();

+

+	virtual GLenum completeness();

+	GLenum completeness(int &width, int &height, int &samples);

+

+protected:

+    GLenum mColorbufferType;

+    BindingPointer<Renderbuffer> mColorbufferPointer;

+

+    GLenum mDepthbufferType;

+    BindingPointer<Renderbuffer> mDepthbufferPointer;

+

+    GLenum mStencilbufferType;

+    BindingPointer<Renderbuffer> mStencilbufferPointer;

+

+private:

+    Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const;

+};

+

+class DefaultFramebuffer : public Framebuffer

+{

+public:

+    DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil);

+

+    virtual GLenum completeness();

+};

+

+}

+

+#endif   // LIBGLESV2_FRAMEBUFFER_H_

diff --git a/src/GLES2/libGLES_CM/HandleAllocator.cpp b/src/GLES2/libGLES_CM/HandleAllocator.cpp
new file mode 100644
index 0000000..7db672a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/HandleAllocator.cpp
@@ -0,0 +1,68 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// HandleAllocator.cpp: Implements the HandleAllocator class, which is used
+// to allocate GL handles.
+
+#include "HandleAllocator.h"
+
+#include "main.h"
+
+namespace gl
+{
+
+HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1)
+{
+}
+
+HandleAllocator::~HandleAllocator()
+{
+}
+
+void HandleAllocator::setBaseHandle(GLuint value)
+{
+    ASSERT(mBaseValue == mNextValue);
+    mBaseValue = value;
+    mNextValue = value;
+}
+
+GLuint HandleAllocator::allocate()
+{
+    if(mFreeValues.size())
+    {
+        GLuint handle = mFreeValues.back();
+        mFreeValues.pop_back();
+        return handle;
+    }
+    return mNextValue++;
+}
+
+void HandleAllocator::release(GLuint handle)
+{
+    if(handle == mNextValue - 1)
+    {
+        // Don't drop below base value
+        if(mNextValue > mBaseValue)
+        {
+            mNextValue--;
+        }
+    }
+    else
+    {
+        // Only free handles that we own - don't drop below the base value
+        if(handle >= mBaseValue)
+        {
+            mFreeValues.push_back(handle);
+        }
+    }
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/HandleAllocator.h b/src/GLES2/libGLES_CM/HandleAllocator.h
new file mode 100644
index 0000000..3dc5a34
--- /dev/null
+++ b/src/GLES2/libGLES_CM/HandleAllocator.h
@@ -0,0 +1,46 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// HandleAllocator.h: Defines the HandleAllocator class, which is used to

+// allocate GL handles.

+

+#ifndef LIBGLESV2_HANDLEALLOCATOR_H_

+#define LIBGLESV2_HANDLEALLOCATOR_H_

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+#include <vector>

+

+namespace gl

+{

+

+class HandleAllocator

+{

+  public:

+    HandleAllocator();

+    virtual ~HandleAllocator();

+

+    void setBaseHandle(GLuint value);

+

+    GLuint allocate();

+    void release(GLuint handle);

+

+  private:

+    GLuint mBaseValue;

+    GLuint mNextValue;

+    typedef std::vector<GLuint> HandleList;

+    HandleList mFreeValues;

+};

+

+}

+

+#endif   // LIBGLESV2_HANDLEALLOCATOR_H_

diff --git a/src/GLES2/libGLES_CM/Image.cpp b/src/GLES2/libGLES_CM/Image.cpp
new file mode 100644
index 0000000..a2950c6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Image.cpp
@@ -0,0 +1,717 @@
+// 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 "Image.hpp"
+
+#include "Texture.h"
+#include "utilities.h"
+#include "../common/debug.h"
+#include "Common/Thread.hpp"
+
+#include <GLES2/gl2ext.h>
+
+namespace gl
+{
+	static sw::Resource *getParentResource(Texture *texture)
+	{
+		if(texture)
+		{
+			return texture->getResource();
+		}
+
+		return 0;
+	}
+
+	Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
+		: parentTexture(parentTexture), width(width), height(height), format(format), type(type)
+		, internalFormat(selectInternalFormat(format, type)), multiSampleDepth(1)
+		, sw::Surface(getParentResource(parentTexture), width, height, 1, selectInternalFormat(format, type), true, true)
+	{
+        shared = false;
+		referenceCount = 1;
+	}
+
+	Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, GLenum format, GLenum type, int multiSampleDepth, bool lockable, bool renderTarget)
+		: parentTexture(parentTexture), width(width), height(height), internalFormat(internalFormat), format(format), type(type), multiSampleDepth(multiSampleDepth)
+		, sw::Surface(getParentResource(parentTexture), width, height, multiSampleDepth, internalFormat, lockable, renderTarget)
+	{
+        shared = false;
+		referenceCount = 1;
+	}
+
+	Image::~Image()
+	{
+		ASSERT(referenceCount == 0);
+	}
+
+	void *Image::lock(unsigned int left, unsigned int top, sw::Lock lock)
+	{
+		return lockExternal(left, top, 0, lock, sw::PUBLIC);
+	}
+
+	unsigned int Image::getPitch() const
+	{
+		return getExternalPitchB();
+	}
+
+	void Image::unlock()
+	{
+		unlockExternal();
+	}
+
+	int Image::getWidth()
+	{
+		return width;
+	}
+	
+	int Image::getHeight()
+	{
+		return height;
+	}
+
+	GLenum Image::getFormat()
+	{
+		return format;
+	}
+	
+	GLenum Image::getType()
+	{
+		return type;
+	}
+	
+	sw::Format Image::getInternalFormat()
+	{
+		return internalFormat;
+	}
+	
+	int Image::getMultiSampleDepth()
+	{
+		return multiSampleDepth;
+	}
+
+	void Image::addRef()
+	{
+		if(parentTexture)
+		{
+			return parentTexture->addRef();
+		}
+
+		sw::atomicIncrement(&referenceCount);
+	}
+
+	void Image::release()
+	{
+		if(parentTexture)
+		{
+			return parentTexture->release();
+		}
+
+		if(referenceCount > 0)
+		{
+			sw::atomicDecrement(&referenceCount);
+		}
+
+		if(referenceCount == 0)
+		{
+			delete this;
+		}
+	}
+
+	void Image::unbind()
+	{
+		parentTexture = 0;
+
+		release();
+	}
+
+    bool Image::isShared() const
+    {
+        return shared;
+    }
+
+    void Image::markShared()
+    {
+        shared = true;
+    }
+
+	sw::Format Image::selectInternalFormat(GLenum format, GLenum type)
+	{
+		#if S3TC_SUPPORT
+		if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+		   format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+		{
+			return sw::FORMAT_DXT1;
+		}
+		else if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
+		{
+			return sw::FORMAT_DXT3;
+		}
+		else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
+		{
+			return sw::FORMAT_DXT5;
+		}
+		else
+		#endif
+		if(type == GL_FLOAT)
+		{
+			return sw::FORMAT_A32B32G32R32F;
+		}
+		else if(type == GL_HALF_FLOAT_OES)
+		{
+			return sw::FORMAT_A16B16G16R16F;
+		}
+		else if(type == GL_UNSIGNED_BYTE)
+		{
+			if(format == GL_LUMINANCE)
+			{
+				return sw::FORMAT_L8;
+			}
+			else if(format == GL_LUMINANCE_ALPHA)
+			{
+				return sw::FORMAT_A8L8;
+			}
+			else if(format == GL_RGBA || format == GL_BGRA_EXT)
+			{
+				return sw::FORMAT_A8R8G8B8;
+			}
+			else if(format == GL_RGB)
+			{
+				return sw::FORMAT_X8R8G8B8;
+			}
+			else if(format == GL_ALPHA)
+			{
+				return sw::FORMAT_A8;
+			}
+			else UNREACHABLE();
+		}
+		else if(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT)
+		{
+			if(format == GL_DEPTH_COMPONENT)
+			{
+				return sw::FORMAT_D32FS8_TEXTURE;
+			}
+			else UNREACHABLE();
+		}
+		else if(type == GL_UNSIGNED_INT_24_8_OES)
+		{
+			if(format == GL_DEPTH_STENCIL_OES)
+			{
+				return sw::FORMAT_D32FS8_TEXTURE;
+			}
+			else UNREACHABLE();
+		}
+		else if(type == GL_UNSIGNED_SHORT_4_4_4_4)
+		{
+			return sw::FORMAT_A8R8G8B8;
+		}
+		else if(type == GL_UNSIGNED_SHORT_5_5_5_1)
+		{
+			return sw::FORMAT_A8R8G8B8;
+		}
+		else if(type == GL_UNSIGNED_SHORT_5_6_5)
+		{
+			return sw::FORMAT_X8R8G8B8;
+		}
+		else UNREACHABLE();
+
+		return sw::FORMAT_A8R8G8B8;
+	}
+
+	int Image::bytes(sw::Format format)
+	{
+		return sw::Surface::bytes(format);
+	}
+
+	void Image::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input)
+	{
+		GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
+		void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
+		
+		if(buffer)
+		{
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				switch(format)
+				{
+				case GL_ALPHA:
+					loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE:
+					loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE_ALPHA:
+					loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGB:
+					loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGBA:
+					loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_BGRA_EXT:
+					loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			case GL_UNSIGNED_SHORT_5_6_5:
+				switch(format)
+				{
+				case GL_RGB:
+					loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			case GL_UNSIGNED_SHORT_4_4_4_4:
+				switch(format)
+				{
+				case GL_RGBA:
+					loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			case GL_UNSIGNED_SHORT_5_5_5_1:
+				switch(format)
+				{
+				case GL_RGBA:
+					loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			case GL_FLOAT:
+				switch(format)
+				{
+				// float textures are converted to RGBA, not BGRA
+				case GL_ALPHA:
+					loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE:
+					loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE_ALPHA:
+					loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGB:
+					loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGBA:
+					loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			  case GL_HALF_FLOAT_OES:
+				switch(format)
+				{
+				// float textures are converted to RGBA, not BGRA
+				case GL_ALPHA:
+					loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE:
+					loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_LUMINANCE_ALPHA:
+					loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGB:
+					loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				case GL_RGBA:
+					loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+				break;
+			case GL_UNSIGNED_SHORT:
+				loadD16ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+				break;
+			case GL_UNSIGNED_INT:
+				loadD32ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+				break;
+			case GL_UNSIGNED_INT_24_8_OES:
+				loadD24S8ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+				break;
+			default: UNREACHABLE();
+			}
+		}
+
+		unlock();
+	}
+
+	void Image::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset;
+
+			memcpy(dest, source, width);
+		}
+	}
+
+	void Image::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = 0;
+				dest[4 * x + 1] = 0;
+				dest[4 * x + 2] = 0;
+				dest[4 * x + 3] = source[x];
+			}
+		}
+	}
+
+	void Image::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = 0;
+				dest[4 * x + 1] = 0;
+				dest[4 * x + 2] = 0;
+				dest[4 * x + 3] = source[x];
+			}
+		}
+	}
+
+	void Image::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset;
+
+			memcpy(dest, source, width);
+		}
+	}
+
+	void Image::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[x];
+				dest[4 * x + 1] = source[x];
+				dest[4 * x + 2] = source[x];
+				dest[4 * x + 3] = 1.0f;
+			}
+		}
+	}
+
+	void Image::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[x];
+				dest[4 * x + 1] = source[x];
+				dest[4 * x + 2] = source[x];
+				dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+			}
+		}
+	}
+
+	void Image::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 2;
+        
+			memcpy(dest, source, width * 2);
+		}
+	}
+
+	void Image::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[2*x+0];
+				dest[4 * x + 1] = source[2*x+0];
+				dest[4 * x + 2] = source[2*x+0];
+				dest[4 * x + 3] = source[2*x+1];
+			}
+		}
+	}
+
+	void Image::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[2*x+0];
+				dest[4 * x + 1] = source[2*x+0];
+				dest[4 * x + 2] = source[2*x+0];
+				dest[4 * x + 3] = source[2*x+1];
+			}
+		}
+	}
+
+	void Image::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[x * 3 + 2];
+				dest[4 * x + 1] = source[x * 3 + 1];
+				dest[4 * x + 2] = source[x * 3 + 0];
+				dest[4 * x + 3] = 0xFF;
+			}
+		}
+	}
+
+	void Image::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+			
+			for(int x = 0; x < width; x++)
+			{
+				unsigned short rgba = source[x];
+				dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
+				dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
+				dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+				dest[4 * x + 3] = 0xFF;
+			}
+		}
+	}
+
+	void Image::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[x * 3 + 0];
+				dest[4 * x + 1] = source[x * 3 + 1];
+				dest[4 * x + 2] = source[x * 3 + 2];
+				dest[4 * x + 3] = 1.0f;
+			}
+		}
+	}
+
+	void Image::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+			
+			for(int x = 0; x < width; x++)
+			{
+				dest[4 * x + 0] = source[x * 3 + 0];
+				dest[4 * x + 1] = source[x * 3 + 1];
+				dest[4 * x + 2] = source[x * 3 + 2];
+				dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+			}
+		}
+	}
+
+	void Image::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+			for(int x = 0; x < width; x++)
+			{
+				unsigned int rgba = source[x];
+				dest[x] = (rgba & 0xFF00FF00) | ((rgba << 16) & 0x00FF0000) | ((rgba >> 16) & 0x000000FF);
+			}
+		}
+	}
+
+	void Image::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+			
+			for(int x = 0; x < width; x++)
+			{
+				unsigned short rgba = source[x];
+				dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+				dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+				dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+				dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+			}
+		}
+	}
+
+	void Image::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+			
+			for(int x = 0; x < width; x++)
+			{
+				unsigned short rgba = source[x];
+				dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+				dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+				dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+				dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+			}
+		}
+	}
+
+	void Image::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+			
+			memcpy(dest, source, width * 16);
+		}
+	}
+
+	void Image::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8;
+			
+			memcpy(dest, source, width * 8);
+		}
+	}
+
+	void Image::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+			unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+			
+			memcpy(dest, source, width*4);
+		}
+	}
+
+	void Image::loadD16ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+			for(int x = 0; x < width; x++)
+			{
+				dest[x] = (float)source[x] / 0xFFFF;
+			}
+		}
+	}
+
+	void Image::loadD32ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+			for(int x = 0; x < width; x++)
+			{
+				dest[x] = (float)source[x] / 0xFFFFFFFF;
+			}
+		}
+	}
+
+	void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer)
+	{
+		for(int y = 0; y < height; y++)
+		{
+			const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+			float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+			for(int x = 0; x < width; x++)
+			{
+				dest[x] = (float)(source[x] & 0xFFFFFF00) / 0xFFFFFF00;
+			}
+		}
+
+		unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, sw::PUBLIC));
+
+		if(stencil)
+		{
+			for(int y = 0; y < height; y++)
+			{
+				const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+				unsigned char *dest = static_cast<unsigned char*>(stencil) + (y + yoffset) * getStencilPitchB() + xoffset;
+
+				for(int x = 0; x < width; x++)
+				{
+					dest[x] = static_cast<unsigned char>(source[x] & 0x000000FF);   // FIXME: Quad layout
+				}
+			}
+
+			unlockStencil();
+		}
+	}
+
+	void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+	{
+		int inputPitch = ComputeCompressedPitch(width, format);
+		int rows = imageSize / inputPitch;
+		void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY);
+
+        if(buffer)
+        {
+			for(int i = 0; i < rows; i++)
+			{
+				memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch);
+			}
+        }
+
+		unlock();
+	}
+}
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/Image.hpp b/src/GLES2/libGLES_CM/Image.hpp
new file mode 100644
index 0000000..faae7d5
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Image.hpp
@@ -0,0 +1,94 @@
+// 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.
+//
+
+#ifndef gl_Image_hpp
+#define gl_Image_hpp
+
+#include "Renderer/Surface.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+	class Texture;
+
+	class Image : public sw::Surface
+	{
+	public:
+		Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type);
+		Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, GLenum format, GLenum type, int multiSampleDepth, bool lockable, bool renderTarget);
+
+		void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input);
+		void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+
+		void *lock(unsigned int left, unsigned int top, sw::Lock lock);
+		unsigned int getPitch() const;
+		void unlock();
+		
+		int getWidth();
+		int getHeight();
+		GLenum getFormat();
+		GLenum getType();
+		virtual sw::Format getInternalFormat();
+		virtual int getMultiSampleDepth();
+
+		virtual void addRef();
+		virtual void release();
+		void unbind();   // Break parent ownership and release
+
+		virtual bool isShared() const;
+		void markShared();
+
+		static sw::Format selectInternalFormat(GLenum format, GLenum type);
+		static int bytes(sw::Format format);
+
+	private:
+		virtual ~Image();
+
+		void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadD16ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadD32ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+		void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer);
+
+		Texture *parentTexture;
+		bool shared;   // Used as an EGLImage
+
+		const GLsizei width;
+		const GLsizei height;
+		const GLenum format;
+		const GLenum type;
+		const sw::Format internalFormat;
+		const int multiSampleDepth;
+
+		volatile int referenceCount;
+	};
+}
+
+#endif   // gl_Image_hpp
diff --git a/src/GLES2/libGLES_CM/IndexDataManager.cpp b/src/GLES2/libGLES_CM/IndexDataManager.cpp
new file mode 100644
index 0000000..3dbfe44
--- /dev/null
+++ b/src/GLES2/libGLES_CM/IndexDataManager.cpp
@@ -0,0 +1,259 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// IndexDataManager.cpp: Defines the IndexDataManager, a class that

+// runs the Buffer translation process for index buffers.

+

+#include "IndexDataManager.h"

+

+#include "Buffer.h"

+#include "common/debug.h"

+

+#include <string.h>

+#include <algorithm>

+

+namespace

+{

+    enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };

+}

+

+namespace gl

+{

+

+IndexDataManager::IndexDataManager()

+{

+    mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);

+

+    if(!mStreamingBuffer)

+    {

+        ERR("Failed to allocate the streaming index buffer.");

+    }

+}

+

+IndexDataManager::~IndexDataManager()

+{

+    delete mStreamingBuffer;

+}

+

+void copyIndices(GLenum type, const void *input, GLsizei count, void *output)

+{

+    if(type == GL_UNSIGNED_BYTE)

+    {

+        memcpy(output, input, count * sizeof(GLubyte));

+    }

+    else if(type == GL_UNSIGNED_INT)

+    {

+        memcpy(output, input, count * sizeof(GLuint));

+    }

+    else if(type == GL_UNSIGNED_SHORT)

+    {

+        memcpy(output, input, count * sizeof(GLushort));

+    }

+    else UNREACHABLE();

+}

+

+template<class IndexType>

+void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)

+{

+    *minIndex = indices[0];

+    *maxIndex = indices[0];

+

+    for(GLsizei i = 0; i < count; i++)

+    {

+        if(*minIndex > indices[i]) *minIndex = indices[i];

+        if(*maxIndex < indices[i]) *maxIndex = indices[i];

+    }

+}

+

+void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)

+{

+    if(type == GL_UNSIGNED_BYTE)

+    {

+        computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);

+    }

+    else if(type == GL_UNSIGNED_INT)

+    {

+        computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);

+    }

+    else if(type == GL_UNSIGNED_SHORT)

+    {

+        computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);

+    }

+    else UNREACHABLE();

+}

+

+GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)

+{

+    if(!mStreamingBuffer)

+    {

+        return GL_OUT_OF_MEMORY;

+    }

+

+    intptr_t offset = reinterpret_cast<intptr_t>(indices);

+    bool alignedOffset = false;

+

+    if(buffer != NULL)

+    {

+        switch(type)

+        {

+          case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;

+          case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;

+          case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;

+          default: UNREACHABLE(); alignedOffset = false;

+        }

+

+        if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))

+        {

+            return GL_INVALID_OPERATION;

+        }

+

+        indices = static_cast<const GLubyte*>(buffer->data()) + offset;

+    }

+

+    StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;

+

+	sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;

+

+    if(staticBuffer)

+    {

+        computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);

+

+		translated->indexBuffer = staticBuffer;

+		translated->indexOffset = offset;

+    }

+    else

+    {

+		unsigned int streamOffset = 0;

+        int convertCount = count;

+

+        streamingBuffer->reserveSpace(convertCount * typeSize(type), type);

+        void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);

+        

+        if(output == NULL)

+        {

+            ERR("Failed to map index buffer.");

+            return GL_OUT_OF_MEMORY;

+        }

+

+        copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);

+        streamingBuffer->unmap();

+

+        computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);

+

+		translated->indexBuffer = streamingBuffer->getResource();

+		translated->indexOffset = streamOffset;

+    }

+

+    return GL_NO_ERROR;

+}

+

+std::size_t IndexDataManager::typeSize(GLenum type)

+{

+    switch(type)

+    {

+    case GL_UNSIGNED_INT:   return sizeof(GLuint);

+    case GL_UNSIGNED_SHORT: return sizeof(GLushort);

+    case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);

+    default: UNREACHABLE(); return sizeof(GLushort);

+    }

+}

+

+StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mBufferSize(initialSize), mIndexBuffer(NULL)

+{

+	if(initialSize > 0)

+    {

+		mIndexBuffer = new sw::Resource(initialSize + 16);

+

+        if(!mIndexBuffer)

+        {

+            ERR("Out of memory allocating an index buffer of size %lu.", initialSize);

+        }

+    }

+

+    mWritePosition = 0;

+}

+

+StreamingIndexBuffer::~StreamingIndexBuffer()

+{

+	if(mIndexBuffer)

+    {

+        mIndexBuffer->destruct();

+    }

+}

+

+void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)

+{

+    void *mapPtr = NULL;

+

+    if(mIndexBuffer)

+    {

+        mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;

+     

+        if(!mapPtr)

+        {

+            ERR(" Lock failed");

+            return NULL;

+        }

+

+        *offset = mWritePosition;

+        mWritePosition += requiredSpace;

+    }

+

+    return mapPtr;

+}

+

+void StreamingIndexBuffer::unmap()

+{

+    if(mIndexBuffer)

+    {

+        mIndexBuffer->unlock();

+    }

+}

+

+void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)

+{

+    if(requiredSpace > mBufferSize)

+    {

+        if(mIndexBuffer)

+        {

+            mIndexBuffer->destruct();

+            mIndexBuffer = 0;

+        }

+

+        mBufferSize = std::max(requiredSpace, 2 * mBufferSize);

+

+		mIndexBuffer = new sw::Resource(mBufferSize + 16);

+    

+        if(!mIndexBuffer)

+        {

+            ERR("Out of memory allocating an index buffer of size %lu.", mBufferSize);

+        }

+

+        mWritePosition = 0;

+    }

+    else if(mWritePosition + requiredSpace > mBufferSize)   // Recycle

+    {

+		if(mIndexBuffer)

+		{

+			mIndexBuffer->destruct();

+			mIndexBuffer = new sw::Resource(mBufferSize + 16);

+		}

+

+        mWritePosition = 0;

+    }

+}

+

+sw::Resource *StreamingIndexBuffer::getResource() const

+{

+    return mIndexBuffer;

+}

+

+}

diff --git a/src/GLES2/libGLES_CM/IndexDataManager.h b/src/GLES2/libGLES_CM/IndexDataManager.h
new file mode 100644
index 0000000..059e9fc
--- /dev/null
+++ b/src/GLES2/libGLES_CM/IndexDataManager.h
@@ -0,0 +1,69 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// IndexDataManager.h: Defines the IndexDataManager, a class that

+// runs the Buffer translation process for index buffers.

+

+#ifndef LIBGLESV2_INDEXDATAMANAGER_H_

+#define LIBGLESV2_INDEXDATAMANAGER_H_

+

+#include "Context.h"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+

+struct TranslatedIndexData

+{

+    unsigned int minIndex;

+    unsigned int maxIndex;

+    unsigned int indexOffset;

+

+    sw::Resource *indexBuffer;

+};

+

+class StreamingIndexBuffer

+{

+  public:

+    StreamingIndexBuffer(unsigned int initialSize);

+    virtual ~StreamingIndexBuffer();

+

+    void *map(unsigned int requiredSpace, unsigned int *offset);

+	void unmap();

+    void reserveSpace(unsigned int requiredSpace, GLenum type);

+

+	sw::Resource *getResource() const;

+

+  private:

+    sw::Resource *mIndexBuffer;

+    unsigned int mBufferSize;

+    unsigned int mWritePosition;

+};

+

+class IndexDataManager

+{

+  public:

+    IndexDataManager();

+    virtual ~IndexDataManager();

+

+    GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);

+

+	static std::size_t typeSize(GLenum type);

+

+  private:

+    StreamingIndexBuffer *mStreamingBuffer;

+};

+

+}

+

+#endif   // LIBGLESV2_INDEXDATAMANAGER_H_

diff --git a/src/GLES2/libGLES_CM/Program.cpp b/src/GLES2/libGLES_CM/Program.cpp
new file mode 100644
index 0000000..ca0ddd6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Program.cpp
@@ -0,0 +1,2294 @@
+// 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.

+//

+

+// Program.cpp: Implements the Program class. Implements GL program objects

+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.

+

+#include "Program.h"

+

+#include "main.h"

+#include "Shader.h"

+#include "utilities.h"

+#include "common/debug.h"

+#include "Shader/PixelShader.hpp"

+#include "Shader/VertexShader.hpp"

+

+#include <string>

+#include <stdlib.h>

+

+namespace gl

+{

+	unsigned int Program::currentSerial = 1;

+

+	std::string str(int i)

+	{

+		char buffer[20];

+		sprintf(buffer, "%d", i);

+		return buffer;

+	}

+

+	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize) : type(type), precision(precision), name(name), arraySize(arraySize)

+	{

+		int bytes = UniformTypeSize(type) * size();

+		data = new unsigned char[bytes];

+		memset(data, 0, bytes);

+		dirty = true;

+

+		psRegisterIndex = -1;

+		vsRegisterIndex = -1;

+	}

+

+	Uniform::~Uniform()

+	{

+		delete[] data;

+	}

+

+	bool Uniform::isArray() const

+	{

+		return arraySize >= 1;

+	}

+

+	int Uniform::size() const

+	{

+		return arraySize > 0 ? arraySize : 1;

+	}

+

+	int Uniform::registerCount() const

+	{

+		return size() * VariableRowCount(type);

+	}

+

+	UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)

+	{

+	}

+

+	Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())

+	{

+		device = getDevice();

+

+		fragmentShader = 0;

+		vertexShader = 0;

+		pixelBinary = 0;

+		vertexBinary = 0;

+

+		infoLog = 0;

+		validated = false;

+

+		unlink();

+

+		orphaned = false;

+		referenceCount = 0;

+	}

+

+	Program::~Program()

+	{

+		unlink();

+

+		if(vertexShader)

+		{

+			vertexShader->release();

+		}

+

+		if(fragmentShader)

+		{

+			fragmentShader->release();

+		}

+	}

+

+	bool Program::attachShader(Shader *shader)

+	{

+		if(shader->getType() == GL_VERTEX_SHADER)

+		{

+			if(vertexShader)

+			{

+				return false;

+			}

+

+			vertexShader = (VertexShader*)shader;

+			vertexShader->addRef();

+		}

+		else if(shader->getType() == GL_FRAGMENT_SHADER)

+		{

+			if(fragmentShader)

+			{

+				return false;

+			}

+

+			fragmentShader = (FragmentShader*)shader;

+			fragmentShader->addRef();

+		}

+		else UNREACHABLE();

+

+		return true;

+	}

+

+	bool Program::detachShader(Shader *shader)

+	{

+		if(shader->getType() == GL_VERTEX_SHADER)

+		{

+			if(vertexShader != shader)

+			{

+				return false;

+			}

+

+			vertexShader->release();

+			vertexShader = 0;

+		}

+		else if(shader->getType() == GL_FRAGMENT_SHADER)

+		{

+			if(fragmentShader != shader)

+			{

+				return false;

+			}

+

+			fragmentShader->release();

+			fragmentShader = 0;

+		}

+		else UNREACHABLE();

+

+		return true;

+	}

+

+	int Program::getAttachedShadersCount() const

+	{

+		return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);

+	}

+

+	sw::PixelShader *Program::getPixelShader()

+	{

+		return pixelBinary;

+	}

+

+	sw::VertexShader *Program::getVertexShader()

+	{

+		return vertexBinary;

+	}

+

+	void Program::bindAttributeLocation(GLuint index, const char *name)

+	{

+		if(index < MAX_VERTEX_ATTRIBS)

+		{

+			for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+			{

+				attributeBinding[i].erase(name);

+			}

+

+			attributeBinding[index].insert(name);

+		}

+	}

+

+	GLuint Program::getAttributeLocation(const char *name)

+	{

+		if(name)

+		{

+			for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)

+			{

+				if(linkedAttribute[index].name == std::string(name))

+				{

+					return index;

+				}

+			}

+		}

+

+		return -1;

+	}

+

+	int Program::getAttributeStream(int attributeIndex)

+	{

+		ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);

+    

+		return attributeStream[attributeIndex];

+	}

+

+	// Returns the index of the texture image unit (0-19) corresponding to a sampler index (0-15 for the pixel shader and 0-3 for the vertex shader)

+	GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)

+	{

+		GLuint logicalTextureUnit = -1;

+

+		switch(type)

+		{

+		case sw::SAMPLER_PIXEL:

+			ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));

+

+			if(samplersPS[samplerIndex].active)

+			{

+				logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;

+			}

+			break;

+		case sw::SAMPLER_VERTEX:

+			ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));

+

+			if(samplersVS[samplerIndex].active)

+			{

+				logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;

+			}

+			break;

+		default: UNREACHABLE();

+		}

+

+		if(logicalTextureUnit >= 0 && logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)

+		{

+			return logicalTextureUnit;

+		}

+

+		return -1;

+	}

+

+	// Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)

+	TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)

+	{

+		switch(type)

+		{

+		case sw::SAMPLER_PIXEL:

+			ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));

+			ASSERT(samplersPS[samplerIndex].active);

+			return samplersPS[samplerIndex].textureType;

+		case sw::SAMPLER_VERTEX:

+			ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));

+			ASSERT(samplersVS[samplerIndex].active);

+			return samplersVS[samplerIndex].textureType;

+		default: UNREACHABLE();

+		}

+

+		return TEXTURE_2D;

+	}

+

+	GLint Program::getUniformLocation(std::string name)

+	{

+		int subscript = 0;

+

+		// Strip any trailing array operator and retrieve the subscript

+		size_t open = name.find_last_of('[');

+		size_t close = name.find_last_of(']');

+		if(open != std::string::npos && close == name.length() - 1)

+		{

+			subscript = atoi(name.substr(open + 1).c_str());

+			name.erase(open);

+		}

+

+		unsigned int numUniforms = uniformIndex.size();

+		for(unsigned int location = 0; location < numUniforms; location++)

+		{

+			if(uniformIndex[location].name == name &&

+			   uniformIndex[location].element == subscript)

+			{

+				return location;

+			}

+		}

+

+		return -1;

+	}

+

+	bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_FLOAT)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat),

+				   v, sizeof(GLfloat) * count);

+		}

+		else if(targetUniform->type == GL_BOOL)

+		{

+			GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element;

+

+			for(int i = 0; i < count; i++)

+			{

+				if(v[i] == 0.0f)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+		}

+		else

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_FLOAT_VEC2)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 2,

+				   v, 2 * sizeof(GLfloat) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC2)

+		{

+			GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 2;

+

+			for(int i = 0; i < count * 2; i++)

+			{

+				if(v[i] == 0.0f)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+		}

+		else 

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_FLOAT_VEC3)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 3,

+				   v, 3 * sizeof(GLfloat) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC3)

+		{

+			GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 3;

+

+			for(int i = 0; i < count * 3; i++)

+			{

+				if(v[i] == 0.0f)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+		}

+		else 

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_FLOAT_VEC4)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,

+				   v, 4 * sizeof(GLfloat) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC4)

+		{

+			GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 4;

+

+			for(int i = 0; i < count * 4; i++)

+			{

+				if(v[i] == 0.0f)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+		}

+		else 

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		if(targetUniform->type != GL_FLOAT_MAT2)

+		{

+			return false;

+		}

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,

+			   value, 4 * sizeof(GLfloat) * count);

+

+		return true;

+	}

+

+	bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		if(targetUniform->type != GL_FLOAT_MAT3)

+		{

+			return false;

+		}

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 9,

+			   value, 9 * sizeof(GLfloat) * count);

+

+		return true;

+	}

+

+	bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		if(targetUniform->type != GL_FLOAT_MAT4)

+		{

+			return false;

+		}

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 16,

+			   value, 16 * sizeof(GLfloat) * count);

+

+		return true;

+	}

+

+	bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_INT ||

+		   targetUniform->type == GL_SAMPLER_2D ||

+		   targetUniform->type == GL_SAMPLER_CUBE ||

+           targetUniform->type == GL_SAMPLER_EXTERNAL_OES)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),

+				   v, sizeof(GLint) * count);

+		}

+		else if(targetUniform->type == GL_BOOL)

+		{

+			GLboolean *boolParams = new GLboolean[count];

+

+			for(int i = 0; i < count; i++)

+			{

+				if(v[i] == 0)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),

+				   boolParams, sizeof(GLboolean) * count);

+

+			delete[] boolParams;

+		}

+		else

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_INT_VEC2)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 2,

+				   v, 2 * sizeof(GLint) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC2)

+		{

+			GLboolean *boolParams = new GLboolean[count * 2];

+

+			for(int i = 0; i < count * 2; i++)

+			{

+				if(v[i] == 0)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 2,

+				   boolParams, 2 * sizeof(GLboolean) * count);

+

+			delete[] boolParams;

+		}

+		else

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_INT_VEC3)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 3,

+				   v, 3 * sizeof(GLint) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC3)

+		{

+			GLboolean *boolParams = new GLboolean[count * 3];

+

+			for(int i = 0; i < count * 3; i++)

+			{

+				if(v[i] == 0)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 3,

+				   boolParams, 3 * sizeof(GLboolean) * count);

+

+			delete[] boolParams;

+		}

+		else

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		targetUniform->dirty = true;

+

+		int size = targetUniform->size();

+

+		if(size == 1 && count > 1)

+		{

+			return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION

+		}

+	

+		count = std::min(size - (int)uniformIndex[location].element, count);

+

+		if(targetUniform->type == GL_INT_VEC4)

+		{

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 4,

+				   v, 4 * sizeof(GLint) * count);

+		}

+		else if(targetUniform->type == GL_BOOL_VEC4)

+		{

+			GLboolean *boolParams = new GLboolean[count * 4];

+

+			for(int i = 0; i < count * 4; i++)

+			{

+				if(v[i] == 0)

+				{

+					boolParams[i] = GL_FALSE;

+				}

+				else

+				{

+					boolParams[i] = GL_TRUE;

+				}

+			}

+

+			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 4,

+				   boolParams, 4 * sizeof(GLboolean) * count);

+

+			delete[] boolParams;

+		}

+		else

+		{

+			return false;

+		}

+

+		return true;

+	}

+

+	bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		unsigned int count = UniformComponentCount(targetUniform->type);

+

+		// Sized query - ensure the provided buffer is large enough

+		if(bufSize && *bufSize < count * sizeof(GLfloat))

+		{

+			return false;

+		}

+

+		switch (UniformComponentType(targetUniform->type))

+		{

+		  case GL_BOOL:

+			{

+				GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;

+

+				for(unsigned int i = 0; i < count; i++)

+				{

+					params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;

+				}

+			}

+			break;

+		  case GL_FLOAT:

+			memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),

+				   count * sizeof(GLfloat));

+			break;

+		  case GL_INT:

+			{

+				GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;

+

+				for(unsigned int i = 0; i < count; i++)

+				{

+					params[i] = (float)intParams[i];

+				}

+			}

+			break;

+		  default: UNREACHABLE();

+		}

+

+		return true;

+	}

+

+	bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)

+	{

+		if(location < 0 || location >= (int)uniformIndex.size())

+		{

+			return false;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+		unsigned int count = UniformComponentCount(targetUniform->type);

+

+		// Sized query - ensure the provided buffer is large enough

+		if(bufSize && *bufSize < count * sizeof(GLint))

+		{

+			return false;

+		}

+

+		switch (UniformComponentType(targetUniform->type))

+		{

+		  case GL_BOOL:

+			{

+				GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;

+

+				for(unsigned int i = 0; i < count; i++)

+				{

+					params[i] = (GLint)boolParams[i];

+				}

+			}

+			break;

+		  case GL_FLOAT:

+			{

+				GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;

+

+				for(unsigned int i = 0; i < count; i++)

+				{

+					params[i] = (GLint)floatParams[i];

+				}

+			}

+			break;

+		  case GL_INT:

+			memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),

+				   count * sizeof(GLint));

+			break;

+		  default: UNREACHABLE();

+		}

+

+		return true;

+	}

+

+	void Program::dirtyAllUniforms()

+	{

+		unsigned int numUniforms = uniforms.size();

+		for(unsigned int index = 0; index < numUniforms; index++)

+		{

+			uniforms[index]->dirty = true;

+		}

+	}

+

+	// Applies all the uniforms set for this program object to the device

+	void Program::applyUniforms()

+	{

+		unsigned int numUniforms = uniformIndex.size();

+		for(unsigned int location = 0; location < numUniforms; location++)

+		{

+			if(uniformIndex[location].element != 0)

+			{

+				continue;

+			}

+

+			Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+			if(targetUniform->dirty)

+			{

+				int size = targetUniform->size();

+				GLfloat *f = (GLfloat*)targetUniform->data;

+				GLint *i = (GLint*)targetUniform->data;

+				GLboolean *b = (GLboolean*)targetUniform->data;

+

+				switch(targetUniform->type)

+				{

+				  case GL_BOOL:       applyUniform1bv(location, size, b);       break;

+				  case GL_BOOL_VEC2:  applyUniform2bv(location, size, b);       break;

+				  case GL_BOOL_VEC3:  applyUniform3bv(location, size, b);       break;

+				  case GL_BOOL_VEC4:  applyUniform4bv(location, size, b);       break;

+				  case GL_FLOAT:      applyUniform1fv(location, size, f);       break;

+				  case GL_FLOAT_VEC2: applyUniform2fv(location, size, f);       break;

+				  case GL_FLOAT_VEC3: applyUniform3fv(location, size, f);       break;

+				  case GL_FLOAT_VEC4: applyUniform4fv(location, size, f);       break;

+				  case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, size, f); break;

+				  case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, size, f); break;

+				  case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, size, f); break;

+				  case GL_SAMPLER_2D:

+				  case GL_SAMPLER_CUBE:

+                  case GL_SAMPLER_EXTERNAL_OES:

+				  case GL_INT:        applyUniform1iv(location, size, i);       break;

+				  case GL_INT_VEC2:   applyUniform2iv(location, size, i);       break;

+				  case GL_INT_VEC3:   applyUniform3iv(location, size, i);       break;

+				  case GL_INT_VEC4:   applyUniform4iv(location, size, i);       break;

+				  default:

+					UNREACHABLE();

+				}

+

+				targetUniform->dirty = false;

+			}

+		}

+	}

+

+	// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111

+	// Returns the number of used varying registers, or -1 if unsuccesful

+	int Program::packVaryings(const Varying *packing[][4])

+	{

+		for(VaryingList::iterator varying = fragmentShader->varyings.begin(); varying != fragmentShader->varyings.end(); varying++)

+		{

+			int n = VariableRowCount(varying->type) * varying->size();

+			int m = VariableColumnCount(varying->type);

+			bool success = false;

+

+			if(m == 2 || m == 3 || m == 4)

+			{

+				for(int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)

+				{

+					bool available = true;

+

+					for(int y = 0; y < n && available; y++)

+					{

+						for(int x = 0; x < m && available; x++)

+						{

+							if(packing[r + y][x])

+							{

+								available = false;

+							}

+						}

+					}

+

+					if(available)

+					{

+						varying->reg = r;

+						varying->col = 0;

+

+						for(int y = 0; y < n; y++)

+						{

+							for(int x = 0; x < m; x++)

+							{

+								packing[r + y][x] = &*varying;

+							}

+						}

+

+						success = true;

+					}

+				}

+

+				if(!success && m == 2)

+				{

+					for(int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)

+					{

+						bool available = true;

+

+						for(int y = 0; y < n && available; y++)

+						{

+							for(int x = 2; x < 4 && available; x++)

+							{

+								if(packing[r + y][x])

+								{

+									available = false;

+								}

+							}

+						}

+

+						if(available)

+						{

+							varying->reg = r;

+							varying->col = 2;

+

+							for(int y = 0; y < n; y++)

+							{

+								for(int x = 2; x < 4; x++)

+								{

+									packing[r + y][x] = &*varying;

+								}

+							}

+

+							success = true;

+						}

+					}

+				}

+			}

+			else if(m == 1)

+			{

+				int space[4] = {0};

+

+				for(int y = 0; y < MAX_VARYING_VECTORS; y++)

+				{

+					for(int x = 0; x < 4; x++)

+					{

+						space[x] += packing[y][x] ? 0 : 1;

+					}

+				}

+

+				int column = 0;

+

+				for(int x = 0; x < 4; x++)

+				{

+					if(space[x] >= n && space[x] < space[column])

+					{

+						column = x;

+					}

+				}

+

+				if(space[column] >= n)

+				{

+					for(int r = 0; r < MAX_VARYING_VECTORS; r++)

+					{

+						if(!packing[r][column])

+						{

+							varying->reg = r;

+

+							for(int y = r; y < r + n; y++)

+							{

+								packing[y][column] = &*varying;

+							}

+

+							break;

+						}

+					}

+

+					varying->col = column;

+

+					success = true;

+				}

+			}

+			else UNREACHABLE();

+

+			if(!success)

+			{

+				appendToInfoLog("Could not pack varying %s", varying->name.c_str());

+

+				return -1;

+			}

+		}

+

+		// Return the number of used registers

+		int registers = 0;

+

+		for(int r = 0; r < MAX_VARYING_VECTORS; r++)

+		{

+			if(packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])

+			{

+				registers++;

+			}

+		}

+

+		return registers;

+	}

+

+	bool Program::linkVaryings()

+	{

+		for(VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); input++)

+		{

+			bool matched = false;

+

+			for(VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); output++)

+			{

+				if(output->name == input->name)

+				{

+					if(output->type != input->type || output->size() != input->size())

+					{

+						appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());

+

+						return false;

+					}

+

+					matched = true;

+					break;

+				}

+			}

+

+			if(!matched)

+			{

+				appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());

+

+				return false;

+			}

+		}

+

+		VaryingList &psVaryings = fragmentShader->varyings;

+		VaryingList &vsVaryings = vertexShader->varyings;

+

+		for(VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); output++)

+		{

+			for(VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); input++)

+			{

+				if(output->name == input->name)

+				{

+					int in = input->reg;

+					int out = output->reg;

+					int components = VariableColumnCount(output->type);

+					int registers = VariableRowCount(output->type) * output->size();

+

+					ASSERT(in >= 0);

+

+					if(in + registers > MAX_VARYING_VECTORS)

+					{

+						appendToInfoLog("Too many varyings");

+						return false;

+					}

+

+					if(out >= 0)

+					{

+						if(out + registers > MAX_VARYING_VECTORS)

+						{

+							appendToInfoLog("Too many varyings");

+							return false;

+						}

+

+						for(int i = 0; i < registers; i++)

+						{

+							if(components >= 1) vertexBinary->output[out + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);

+							if(components >= 2) vertexBinary->output[out + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);

+							if(components >= 3) vertexBinary->output[out + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);

+							if(components >= 4) vertexBinary->output[out + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);

+						}

+					}

+					else   // Vertex varying is declared but not written to

+					{

+						for(int i = 0; i < registers; i++)

+						{

+							if(components >= 1) pixelBinary->semantic[in + i][0] = sw::Shader::Semantic();

+							if(components >= 2) pixelBinary->semantic[in + i][1] = sw::Shader::Semantic();

+							if(components >= 3) pixelBinary->semantic[in + i][2] = sw::Shader::Semantic();

+							if(components >= 4) pixelBinary->semantic[in + i][3] = sw::Shader::Semantic();					

+						}

+					}

+

+					break;

+				}

+			}

+		}

+

+		return true;

+	}

+

+	// Links the code of the vertex and pixel shader by matching up their varyings,

+	// compiling them into binaries, determining the attribute mappings, and collecting

+	// a list of uniforms

+	void Program::link()

+	{

+		unlink();

+

+		if(!fragmentShader || !fragmentShader->isCompiled())

+		{

+			return;

+		}

+

+		if(!vertexShader || !vertexShader->isCompiled())

+		{

+			return;

+		}

+

+		vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());

+		pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());

+			

+		if(!linkVaryings())

+		{

+			return;

+		}

+

+		if(!linkAttributes())

+		{

+			return;

+		}

+

+		if(!linkUniforms(fragmentShader))

+		{

+			return;

+		}

+

+		if(!linkUniforms(vertexShader))

+		{

+			return;

+		}

+

+		linked = true;   // Success

+	}

+

+	// Determines the mapping between GL attributes and vertex stream usage indices

+	bool Program::linkAttributes()

+	{

+		unsigned int usedLocations = 0;

+

+		// Link attributes that have a binding location

+		for(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)

+		{

+			int location = getAttributeBinding(attribute->name);

+

+			if(location != -1)   // Set by glBindAttribLocation

+			{

+				if(!linkedAttribute[location].name.empty())

+				{

+					// Multiple active attributes bound to the same location; not an error

+				}

+

+				linkedAttribute[location] = *attribute;

+

+				int rows = VariableRowCount(attribute->type);

+

+				if(rows + location > MAX_VERTEX_ATTRIBS)

+				{

+					appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);

+					return false;

+				}

+

+				for(int i = 0; i < rows; i++)

+				{

+					usedLocations |= 1 << (location + i);

+				}

+			}

+		}

+

+		// Link attributes that don't have a binding location

+		for(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)

+		{

+			int location = getAttributeBinding(attribute->name);

+

+			if(location == -1)   // Not set by glBindAttribLocation

+			{

+				int rows = VariableRowCount(attribute->type);

+				int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);

+

+				if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)

+				{

+					appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());

+					return false;   // Fail to link

+				}

+

+				linkedAttribute[availableIndex] = *attribute;

+			}

+		}

+

+		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )

+		{

+			int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);

+			int rows = std::max(VariableRowCount(linkedAttribute[attributeIndex].type), 1);

+

+			for(int r = 0; r < rows; r++)

+			{

+				attributeStream[attributeIndex++] = index++;

+			}

+		}

+

+		return true;

+	}

+

+	int Program::getAttributeBinding(const std::string &name)

+	{

+		for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)

+		{

+			if(attributeBinding[location].find(name) != attributeBinding[location].end())

+			{

+				return location;

+			}

+		}

+

+		return -1;

+	}

+

+	bool Program::linkUniforms(Shader *shader)

+	{

+		const sh::ActiveUniforms &activeUniforms = shader->activeUniforms;

+

+		for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)

+		{

+			const sh::Uniform &uniform = activeUniforms[uniformIndex];

+

+			if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex))

+			{

+				return false;

+			}

+		}

+

+		return true;

+	}

+

+	bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)

+	{

+		if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES)

+	    {

+			int index = registerIndex;

+			

+			do

+			{

+				if(shader == GL_VERTEX_SHADER)

+				{

+					if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)

+					{

+						samplersVS[index].active = true;

+						samplersVS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;

+						samplersVS[index].logicalTextureUnit = 0;

+					}

+					else

+					{

+					   appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);

+					   return false;

+					}

+				}

+				else if(shader == GL_FRAGMENT_SHADER)

+				{

+					if(index < MAX_TEXTURE_IMAGE_UNITS)

+					{

+						samplersPS[index].active = true;

+						samplersPS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;

+						samplersPS[index].logicalTextureUnit = 0;

+					}

+					else

+					{

+						appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);

+						return false;

+					}

+				}

+				else UNREACHABLE();

+

+				index++;

+			}

+			while(index < registerIndex + arraySize);

+	    }

+

+		Uniform *uniform = 0;

+		GLint location = getUniformLocation(name);

+

+		if(location >= 0)   // Previously defined, types must match

+		{

+			uniform = uniforms[uniformIndex[location].index];

+

+			if(uniform->type != type)

+			{

+				appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());

+				return false;

+			}

+

+			if(uniform->precision != precision)

+			{

+				appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());

+				return false;

+			}

+		}

+		else

+		{

+			uniform = new Uniform(type, precision, name, arraySize);

+		}

+

+		if(!uniform)

+		{

+			return false;

+		}

+

+		if(shader == GL_VERTEX_SHADER)

+		{

+			uniform->vsRegisterIndex = registerIndex;

+		}

+		else if(shader == GL_FRAGMENT_SHADER)

+		{

+			uniform->psRegisterIndex = registerIndex;

+		}

+		else UNREACHABLE();

+

+		if(location == -1)   // Not previously defined

+		{

+			uniforms.push_back(uniform);

+			unsigned int index = uniforms.size() - 1;

+

+			for(unsigned int i = 0; i < uniform->size(); i++)

+			{

+				uniformIndex.push_back(UniformLocation(name, i, index));

+			}

+		}

+

+		if(shader == GL_VERTEX_SHADER)

+		{

+			if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)

+			{

+				appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);

+				return false;

+			}

+		}

+		else if(shader == GL_FRAGMENT_SHADER)

+		{

+			if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)

+			{

+				appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);

+				return false;

+			}

+		}

+		else UNREACHABLE();

+

+		return true;

+	}

+

+	bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)

+	{

+		int vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][1] = 0;

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+

+			v += 1;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)

+	{

+		int vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+

+			v += 2;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)

+	{

+		int vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][3] = 0;

+

+			v += 3;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)

+	{

+		int vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+			vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);

+

+			v += 4;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = v[0];

+			vector[i][1] = 0;

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+

+			v += 1;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = v[0];

+			vector[i][1] = v[1];

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+

+			v += 2;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = v[0];

+			vector[i][1] = v[1];

+			vector[i][2] = v[2];

+			vector[i][3] = 0;

+

+			v += 3;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)

+	{

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)v, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)v, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			matrix[i][0][0] = value[0];	matrix[i][0][1] = value[1];	matrix[i][0][2] = 0; matrix[i][0][3] = 0;

+			matrix[i][1][0] = value[2];	matrix[i][1][1] = value[3];	matrix[i][1][2] = 0; matrix[i][1][3] = 0;

+

+			value += 4;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			matrix[i][0][0] = value[0];	matrix[i][0][1] = value[1];	matrix[i][0][2] = value[2];	matrix[i][0][3] = 0;

+			matrix[i][1][0] = value[3];	matrix[i][1][1] = value[4];	matrix[i][1][2] = value[5];	matrix[i][1][3] = 0;

+			matrix[i][2][0] = value[6];	matrix[i][2][1] = value[7];	matrix[i][2][2] = value[8];	matrix[i][2][3] = 0;

+

+			value += 9;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{	

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)

+	{

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+	

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)value, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)value, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (float)v[i];

+			vector[i][1] = 0;

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+            if(targetUniform->type == GL_SAMPLER_2D ||

+               targetUniform->type == GL_SAMPLER_CUBE ||

+               targetUniform->type == GL_SAMPLER_EXTERNAL_OES)

+			{

+				for(int i = 0; i < count; i++)

+				{

+					unsigned int samplerIndex = targetUniform->psRegisterIndex + i;

+

+					if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)

+					{

+						ASSERT(samplersPS[samplerIndex].active);

+						samplersPS[samplerIndex].logicalTextureUnit = v[i];

+					}

+				}

+			}

+			else

+			{

+				device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+			}

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			if(targetUniform->type == GL_SAMPLER_2D ||

+               targetUniform->type == GL_SAMPLER_CUBE ||

+               targetUniform->type == GL_SAMPLER_EXTERNAL_OES)

+			{

+				for(int i = 0; i < count; i++)

+				{

+					unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;

+

+					if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)

+					{

+						ASSERT(samplersVS[samplerIndex].active);

+						samplersVS[samplerIndex].logicalTextureUnit = v[i];

+					}

+				}

+			}

+			else

+			{

+				device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+			}

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (float)v[0];

+			vector[i][1] = (float)v[1];

+			vector[i][2] = 0;

+			vector[i][3] = 0;

+

+			v += 2;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (float)v[0];

+			vector[i][1] = (float)v[1];

+			vector[i][2] = (float)v[2];

+			vector[i][3] = 0;

+

+			v += 3;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)

+	{

+		float vector[MAX_UNIFORM_VECTORS][4];

+

+		for(int i = 0; i < count; i++)

+		{

+			vector[i][0] = (float)v[0];

+			vector[i][1] = (float)v[1];

+			vector[i][2] = (float)v[2];

+			vector[i][3] = (float)v[3];

+

+			v += 4;

+		}

+

+		Uniform *targetUniform = uniforms[uniformIndex[location].index];

+

+		if(targetUniform->psRegisterIndex != -1)

+		{

+			device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		if(targetUniform->vsRegisterIndex != -1)

+		{

+			device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());

+		}

+

+		return true;

+	}

+

+	void Program::appendToInfoLog(const char *format, ...)

+	{

+		if(!format)

+		{

+			return;

+		}

+

+		char info[1024];

+

+		va_list vararg;

+		va_start(vararg, format);

+		vsnprintf(info, sizeof(info), format, vararg);

+		va_end(vararg);

+

+		size_t infoLength = strlen(info);

+

+		if(!infoLog)

+		{

+			infoLog = new char[infoLength + 2];

+			strcpy(infoLog, info);

+			strcpy(infoLog + infoLength, "\n");

+		}

+		else

+		{

+			size_t logLength = strlen(infoLog);

+			char *newLog = new char[logLength + infoLength + 2];

+			strcpy(newLog, infoLog);

+			strcpy(newLog + logLength, info);

+			strcpy(newLog + logLength + infoLength, "\n");

+

+			delete[] infoLog;

+			infoLog = newLog;

+		}

+	}

+

+	void Program::resetInfoLog()

+	{

+		if(infoLog)

+		{

+			delete[] infoLog;

+			infoLog = 0;

+		}

+	}

+

+	// Returns the program object to an unlinked state, before re-linking, or at destruction

+	void Program::unlink()

+	{

+		delete vertexBinary;

+		vertexBinary = 0;

+		delete pixelBinary;

+		pixelBinary = 0;

+

+		for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)

+		{

+			linkedAttribute[index].name.clear();

+			attributeStream[index] = -1;

+		}

+

+		for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)

+		{

+			samplersPS[index].active = false;

+		}

+

+		for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)

+		{

+			samplersVS[index].active = false;

+		}

+

+		while(!uniforms.empty())

+		{

+			delete uniforms.back();

+			uniforms.pop_back();

+		}

+

+		uniformIndex.clear();

+

+		delete[] infoLog;

+		infoLog = 0;

+

+		linked = false;

+	}

+

+	bool Program::isLinked()

+	{

+		return linked;

+	}

+

+	bool Program::isValidated() const 

+	{

+		return validated;

+	}

+

+	void Program::release()

+	{

+		referenceCount--;

+

+		if(referenceCount == 0 && orphaned)

+		{

+			resourceManager->deleteProgram(handle);

+		}

+	}

+

+	void Program::addRef()

+	{

+		referenceCount++;

+	}

+

+	unsigned int Program::getRefCount() const

+	{

+		return referenceCount;

+	}

+

+	unsigned int Program::getSerial() const

+	{

+		return serial;

+	}

+

+	unsigned int Program::issueSerial()

+	{

+		return currentSerial++;

+	}

+

+	int Program::getInfoLogLength() const

+	{

+		if(!infoLog)

+		{

+			return 0;

+		}

+		else

+		{

+		   return strlen(infoLog) + 1;

+		}

+	}

+

+	void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)

+	{

+		int index = 0;

+

+		if(bufSize > 0)

+		{

+			if(infoLog)

+			{

+				index = std::min(bufSize - 1, (int)strlen(infoLog));

+				memcpy(buffer, infoLog, index);

+			}

+

+			buffer[index] = '\0';

+		}

+

+		if(length)

+		{

+			*length = index;

+		}

+	}

+

+	void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)

+	{

+		int total = 0;

+

+		if(vertexShader)

+		{

+			if(total < maxCount)

+			{

+				shaders[total] = vertexShader->getHandle();

+			}

+

+			total++;

+		}

+

+		if(fragmentShader)

+		{

+			if(total < maxCount)

+			{

+				shaders[total] = fragmentShader->getHandle();

+			}

+

+			total++;

+		}

+

+		if(count)

+		{

+			*count = total;

+		}

+	}

+

+	void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const

+	{

+		// Skip over inactive attributes

+		unsigned int activeAttribute = 0;

+		unsigned int attribute;

+		for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)

+		{

+			if(linkedAttribute[attribute].name.empty())

+			{

+				continue;

+			}

+

+			if(activeAttribute == index)

+			{

+				break;

+			}

+

+			activeAttribute++;

+		}

+

+		if(bufsize > 0)

+		{

+			const char *string = linkedAttribute[attribute].name.c_str();

+

+			strncpy(name, string, bufsize);

+			name[bufsize - 1] = '\0';

+

+			if(length)

+			{

+				*length = strlen(name);

+			}

+		}

+

+		*size = 1;   // Always a single 'type' instance

+

+		*type = linkedAttribute[attribute].type;

+	}

+

+	GLint Program::getActiveAttributeCount() const

+	{

+		int count = 0;

+

+		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)

+		{

+			if(!linkedAttribute[attributeIndex].name.empty())

+			{

+				count++;

+			}

+		}

+

+		return count;

+	}

+

+	GLint Program::getActiveAttributeMaxLength() const

+	{

+		int maxLength = 0;

+

+		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)

+		{

+			if(!linkedAttribute[attributeIndex].name.empty())

+			{

+				maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);

+			}

+		}

+

+		return maxLength;

+	}

+

+	void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const

+	{

+		if(bufsize > 0)

+		{

+			std::string string = uniforms[index]->name;

+

+			if(uniforms[index]->isArray())

+			{

+				string += "[0]";

+			}

+

+			strncpy(name, string.c_str(), bufsize);

+			name[bufsize - 1] = '\0';

+

+			if(length)

+			{

+				*length = strlen(name);

+			}

+		}

+

+		*size = uniforms[index]->size();

+

+		*type = uniforms[index]->type;

+	}

+

+	GLint Program::getActiveUniformCount() const

+	{

+		return uniforms.size();

+	}

+

+	GLint Program::getActiveUniformMaxLength() const

+	{

+		int maxLength = 0;

+

+		unsigned int numUniforms = uniforms.size();

+		for(unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)

+		{

+			if(!uniforms[uniformIndex]->name.empty())

+			{

+				int length = (int)(uniforms[uniformIndex]->name.length() + 1);

+				if(uniforms[uniformIndex]->isArray())

+				{

+					length += 3;  // Counting in "[0]".

+				}

+				maxLength = std::max(length, maxLength);

+			}

+		}

+

+		return maxLength;

+	}

+

+	void Program::flagForDeletion()

+	{

+		orphaned = true;

+	}

+

+	bool Program::isFlaggedForDeletion() const

+	{

+		return orphaned;

+	}

+

+	void Program::validate()

+	{

+		resetInfoLog();

+

+		if(!isLinked()) 

+		{

+			appendToInfoLog("Program has not been successfully linked.");

+			validated = false;

+		}

+		else

+		{

+			applyUniforms();

+			if(!validateSamplers(true))

+			{

+				validated = false;

+			}

+			else

+			{

+				validated = true;

+			}

+		}

+	}

+

+	bool Program::validateSamplers(bool logErrors)

+	{

+		// if any two active samplers in a program are of different types, but refer to the same

+		// texture image unit, and this is the current program, then ValidateProgram will fail, and

+		// DrawArrays and DrawElements will issue the INVALID_OPERATION error.

+

+		TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];

+

+		for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)

+		{

+			textureUnitType[i] = TEXTURE_UNKNOWN;

+		}

+

+		for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)

+		{

+			if(samplersPS[i].active)

+			{

+				unsigned int unit = samplersPS[i].logicalTextureUnit;

+            

+				if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)

+				{

+					if(logErrors)

+					{

+						appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);

+					}

+

+					return false;

+				}

+

+				if(textureUnitType[unit] != TEXTURE_UNKNOWN)

+				{

+					if(samplersPS[i].textureType != textureUnitType[unit])

+					{

+						if(logErrors)

+						{

+							appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);

+						}

+

+						return false;

+					}

+				}

+				else

+				{

+					textureUnitType[unit] = samplersPS[i].textureType;

+				}

+			}

+		}

+

+		for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)

+		{

+			if(samplersVS[i].active)

+			{

+				unsigned int unit = samplersVS[i].logicalTextureUnit;

+            

+				if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)

+				{

+					if(logErrors)

+					{

+						appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);

+					}

+

+					return false;

+				}

+

+				if(textureUnitType[unit] != TEXTURE_UNKNOWN)

+				{

+					if(samplersVS[i].textureType != textureUnitType[unit])

+					{

+						if(logErrors)

+						{

+							appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);

+						}

+

+						return false;

+					}

+				}

+				else

+				{

+					textureUnitType[unit] = samplersVS[i].textureType;

+				}

+			}

+		}

+

+		return true;

+	}

+}

diff --git a/src/GLES2/libGLES_CM/Program.h b/src/GLES2/libGLES_CM/Program.h
new file mode 100644
index 0000000..33e358c
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Program.h
@@ -0,0 +1,207 @@
+// 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.

+//

+

+// Program.h: Defines the Program class. Implements GL program objects

+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.

+

+#ifndef LIBGLESV2_PROGRAM_H_

+#define LIBGLESV2_PROGRAM_H_

+

+#include "Shader.h"

+#include "Context.h"

+#include "Shader/PixelShader.hpp"

+#include "Shader/VertexShader.hpp"

+

+#include <string>

+#include <vector>

+#include <set>

+

+namespace gl

+{

+	class Device;

+	class ResourceManager;

+	class FragmentShader;

+	class VertexShader;

+

+	// Helper struct representing a single shader uniform

+	struct Uniform

+	{

+		Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize);

+

+		~Uniform();

+

+		bool isArray() const;

+		int size() const;

+		int registerCount() const;

+

+		const GLenum type;

+		const GLenum precision;

+		const std::string name;

+		const unsigned int arraySize;

+

+		unsigned char *data;

+		bool dirty;

+

+		short psRegisterIndex;

+		short vsRegisterIndex;

+	};

+

+	// Struct used for correlating uniforms/elements of uniform arrays to handles

+	struct UniformLocation

+	{

+		UniformLocation(const std::string &name, unsigned int element, unsigned int index);

+

+		std::string name;

+		unsigned int element;

+		unsigned int index;

+	};

+

+	class Program

+	{

+	public:

+		Program(ResourceManager *manager, GLuint handle);

+

+		~Program();

+

+		bool attachShader(Shader *shader);

+		bool detachShader(Shader *shader);

+		int getAttachedShadersCount() const;

+

+		sw::PixelShader *getPixelShader();

+		sw::VertexShader *getVertexShader();

+

+		void bindAttributeLocation(GLuint index, const char *name);

+		GLuint getAttributeLocation(const char *name);

+		int getAttributeStream(int attributeIndex);

+

+		GLint getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex);

+		TextureType getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex);

+

+		GLint getUniformLocation(std::string name);

+		bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v);

+		bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v);

+		bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v);

+		bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v);

+		bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);

+		bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);

+		bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);

+		bool setUniform1iv(GLint location, GLsizei count, const GLint *v);

+		bool setUniform2iv(GLint location, GLsizei count, const GLint *v);

+		bool setUniform3iv(GLint location, GLsizei count, const GLint *v);

+		bool setUniform4iv(GLint location, GLsizei count, const GLint *v);

+

+		bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params);

+		bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params);

+

+		void dirtyAllUniforms();

+		void applyUniforms();

+

+		void link();

+		bool isLinked();

+		int getInfoLogLength() const;

+		void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);

+		void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);

+

+		void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;

+		GLint getActiveAttributeCount() const;

+		GLint getActiveAttributeMaxLength() const;

+

+		void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;

+		GLint getActiveUniformCount() const;

+		GLint getActiveUniformMaxLength() const;

+

+		void addRef();

+		void release();

+		unsigned int getRefCount() const;

+		void flagForDeletion();

+		bool isFlaggedForDeletion() const;

+

+		void validate();

+		bool validateSamplers(bool logErrors);

+		bool isValidated() const;

+

+		unsigned int getSerial() const;

+

+	private:

+		void unlink();

+

+		int packVaryings(const Varying *packing[][4]);

+		bool linkVaryings();

+

+		bool linkAttributes();

+		int getAttributeBinding(const std::string &name);

+

+		bool linkUniforms(Shader *shader);

+		bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex);

+		bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v);

+		bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v);

+		bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v);

+		bool applyUniform4bv(GLint location, GLsizei count, const GLboolean *v);

+		bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v);

+		bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v);

+		bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v);

+		bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v);

+		bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);

+		bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);

+		bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);

+		bool applyUniform1iv(GLint location, GLsizei count, const GLint *v);

+		bool applyUniform2iv(GLint location, GLsizei count, const GLint *v);

+		bool applyUniform3iv(GLint location, GLsizei count, const GLint *v);

+		bool applyUniform4iv(GLint location, GLsizei count, const GLint *v);    

+

+		void appendToInfoLog(const char *info, ...);

+		void resetInfoLog();

+

+		static unsigned int issueSerial();

+

+	private:

+		gl::Device *device;

+		FragmentShader *fragmentShader;

+		VertexShader *vertexShader;

+

+		sw::PixelShader *pixelBinary;

+		sw::VertexShader *vertexBinary;

+    

+		std::set<std::string> attributeBinding[MAX_VERTEX_ATTRIBS];

+		sh::Attribute linkedAttribute[MAX_VERTEX_ATTRIBS];

+		int attributeStream[MAX_VERTEX_ATTRIBS];

+

+		struct Sampler

+		{

+			bool active;

+			GLint logicalTextureUnit;

+			TextureType textureType;

+		};

+

+		Sampler samplersPS[MAX_TEXTURE_IMAGE_UNITS];

+		Sampler samplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS];

+

+		typedef std::vector<Uniform*> UniformArray;

+		UniformArray uniforms;

+		typedef std::vector<UniformLocation> UniformIndex;

+		UniformIndex uniformIndex;

+

+		bool linked;

+		bool orphaned;   // Flag to indicate that the program can be deleted when no longer in use

+		char *infoLog;

+		bool validated;

+

+		unsigned int referenceCount;

+		const unsigned int serial;

+

+		static unsigned int currentSerial;

+

+		ResourceManager *resourceManager;

+		const GLuint handle;

+	};

+}

+

+#endif   // LIBGLESV2_PROGRAM_H_

diff --git a/src/GLES2/libGLES_CM/Query.cpp b/src/GLES2/libGLES_CM/Query.cpp
new file mode 100644
index 0000000..8e69d70
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Query.cpp
@@ -0,0 +1,127 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// Query.cpp: Implements the gl::Query class

+

+#include "Query.h"

+

+#include "main.h"

+#include "Common/Thread.hpp"

+

+namespace gl

+{

+

+Query::Query(GLuint id, GLenum type) : RefCountObject(id)

+{ 

+    mQuery = NULL;

+    mStatus = GL_FALSE;

+    mResult = GL_FALSE;

+    mType = type;

+}

+

+Query::~Query()

+{

+    if(mQuery != NULL)

+    {

+        delete mQuery;

+    }

+}

+

+void Query::begin()

+{

+    if(mQuery == NULL)

+    {

+		mQuery = new sw::Query();

+        

+		if(!mQuery)

+        {

+            return error(GL_OUT_OF_MEMORY);

+        }

+    }

+

+	Device *device = getDevice();

+

+	mQuery->begin();

+	device->addQuery(mQuery);

+	device->setOcclusionEnabled(true);

+}

+

+void Query::end()

+{

+    if(mQuery == NULL)

+    {

+        return error(GL_INVALID_OPERATION);

+	}

+

+	Device *device = getDevice();

+

+    mQuery->end();

+	device->removeQuery(mQuery);

+	device->setOcclusionEnabled(false);

+    

+    mStatus = GL_FALSE;

+    mResult = GL_FALSE;

+}

+

+GLuint Query::getResult()

+{

+    if(mQuery != NULL)

+    {

+        while(!testQuery())

+        {

+            sw::Thread::yield();

+        }

+    }

+

+    return (GLuint)mResult;

+}

+

+GLboolean Query::isResultAvailable()

+{

+    if(mQuery != NULL)

+    {

+        testQuery();

+    }

+    

+    return mStatus;

+}

+

+GLenum Query::getType() const

+{

+    return mType;

+}

+

+GLboolean Query::testQuery()

+{

+    if(mQuery != NULL && mStatus != GL_TRUE)

+    {

+        if(!mQuery->building && mQuery->reference == 0)

+        {

+			unsigned int numPixels = mQuery->data;

+            mStatus = GL_TRUE;

+

+            switch(mType)

+            {

+            case GL_ANY_SAMPLES_PASSED_EXT:

+            case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:

+                mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;

+                break;

+            default:

+                ASSERT(false);

+            }

+        }

+        

+        return mStatus;

+    }

+

+    return GL_TRUE;   // Prevent blocking when query is null

+}

+}

diff --git a/src/GLES2/libGLES_CM/Query.h b/src/GLES2/libGLES_CM/Query.h
new file mode 100644
index 0000000..a80456e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Query.h
@@ -0,0 +1,50 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// Query.h: Defines the gl::Query class

+

+#ifndef LIBGLESV2_QUERY_H_

+#define LIBGLESV2_QUERY_H_

+

+#include "RefCountObject.h"

+#include "Renderer/Renderer.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+

+class Query : public RefCountObject

+{

+  public:

+    Query(GLuint id, GLenum type);

+    virtual ~Query();

+

+    void begin();

+    void end();

+    GLuint getResult();

+    GLboolean isResultAvailable();

+

+    GLenum getType() const;

+

+  private:

+    GLboolean testQuery();

+

+    sw::Query* mQuery;

+    GLenum mType;

+    GLboolean mStatus;

+    GLint mResult;

+};

+

+}

+

+#endif   // LIBGLESV2_QUERY_H_

diff --git a/src/GLES2/libGLES_CM/RefCountObject.cpp b/src/GLES2/libGLES_CM/RefCountObject.cpp
new file mode 100644
index 0000000..b470ab2
--- /dev/null
+++ b/src/GLES2/libGLES_CM/RefCountObject.cpp
@@ -0,0 +1,65 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// RefCountObject.cpp: Defines the RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#include "RefCountObject.h"
+
+#include "Common/Thread.hpp"
+
+namespace gl
+{
+
+RefCountObject::RefCountObject(GLuint id)
+{
+    mId = id;
+    
+	referenceCount = 0;
+}
+
+RefCountObject::~RefCountObject()
+{
+    ASSERT(referenceCount == 0);
+}
+
+void RefCountObject::addRef()
+{
+	sw::atomicIncrement(&referenceCount);
+}
+
+void RefCountObject::release()
+{
+    ASSERT(referenceCount > 0);
+
+    if(referenceCount > 0)
+	{
+		sw::atomicDecrement(&referenceCount);
+	}
+
+	if(referenceCount == 0)
+	{
+		delete this;
+	}
+}
+
+void RefCountObjectBindingPointer::set(RefCountObject *newObject)
+{
+    // addRef first in case newObject == mObject and this is the last reference to it.
+    if(newObject != NULL) newObject->addRef();
+    if(mObject != NULL) mObject->release();
+
+    mObject = newObject;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/RefCountObject.h b/src/GLES2/libGLES_CM/RefCountObject.h
new file mode 100644
index 0000000..a9a11e0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/RefCountObject.h
@@ -0,0 +1,75 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// RefCountObject.h: Defines the RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#ifndef LIBGLESV2_REFCOUNTOBJECT_H_
+#define LIBGLESV2_REFCOUNTOBJECT_H_
+
+#include "common/debug.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <cstddef>
+
+namespace gl
+{
+
+class RefCountObject
+{
+  public:
+    explicit RefCountObject(GLuint id);
+    virtual ~RefCountObject();
+
+    virtual void addRef();
+	virtual void release();
+
+    GLuint id() const {return mId;}
+    
+  private:
+    GLuint mId;
+
+    volatile int referenceCount;
+};
+
+class RefCountObjectBindingPointer
+{
+  protected:
+    RefCountObjectBindingPointer() : mObject(NULL) { }
+    ~RefCountObjectBindingPointer() { ASSERT(mObject == NULL); } // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
+
+    void set(RefCountObject *newObject);
+    RefCountObject *get() const { return mObject; }
+
+  public:
+    GLuint id() const { return (mObject != NULL) ? mObject->id() : 0; }
+    bool operator ! () const { return (get() == NULL); }
+
+  private:
+    RefCountObject *mObject;
+};
+
+template<class ObjectType>
+class BindingPointer : public RefCountObjectBindingPointer
+{
+  public:
+    void set(ObjectType *newObject) { RefCountObjectBindingPointer::set(newObject); }
+    ObjectType *get() const { return static_cast<ObjectType*>(RefCountObjectBindingPointer::get()); }
+    ObjectType *operator -> () const { return get(); }
+};
+
+}
+
+#endif   // LIBGLESV2_REFCOUNTOBJECT_H_
diff --git a/src/GLES2/libGLES_CM/Renderbuffer.cpp b/src/GLES2/libGLES_CM/Renderbuffer.cpp
new file mode 100644
index 0000000..6ca0c15
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Renderbuffer.cpp
@@ -0,0 +1,557 @@
+// 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.
+//
+
+// Renderbuffer.cpp: the Renderbuffer class and its derived classes
+// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
+
+#include "Renderbuffer.h"
+
+#include "main.h"
+#include "Texture.h"
+#include "utilities.h"
+
+namespace gl
+{
+RenderbufferInterface::RenderbufferInterface()
+{
+}
+
+// The default case for classes inherited from RenderbufferInterface is not to
+// need to do anything upon the reference count to the parent Renderbuffer incrementing
+// or decrementing. 
+void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy)
+{
+}
+
+void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy)
+{
+}
+
+GLuint RenderbufferInterface::getRedSize() const
+{
+	return sw2es::GetRedSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getGreenSize() const
+{
+	return sw2es::GetGreenSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getBlueSize() const
+{
+	return sw2es::GetBlueSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getAlphaSize() const
+{
+	return sw2es::GetAlphaSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getDepthSize() const
+{
+	return sw2es::GetDepthSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getStencilSize() const
+{
+	return sw2es::GetStencilSize(getInternalFormat());
+}
+
+///// RenderbufferTexture2D Implementation ////////
+
+RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture)
+{
+	mTexture2D.set(texture);
+}
+
+RenderbufferTexture2D::~RenderbufferTexture2D()
+{
+	mTexture2D.set(NULL);
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy)
+{
+    mTexture2D->addProxyRef(proxy);
+}
+
+void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy)
+{
+    mTexture2D->releaseProxy(proxy);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTexture2D::getRenderTarget()
+{
+	return mTexture2D->getRenderTarget(GL_TEXTURE_2D, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTexture2D::createSharedImage()
+{
+    return mTexture2D->createSharedImage(GL_TEXTURE_2D, 0);
+}
+
+bool RenderbufferTexture2D::isShared() const
+{
+    return mTexture2D->isShared(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getWidth() const
+{
+	return mTexture2D->getWidth(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getHeight() const
+{
+	return mTexture2D->getHeight(GL_TEXTURE_2D, 0);
+}
+
+GLenum RenderbufferTexture2D::getFormat() const
+{
+	return mTexture2D->getFormat(GL_TEXTURE_2D, 0);
+}
+
+sw::Format RenderbufferTexture2D::getInternalFormat() const
+{
+	return mTexture2D->getInternalFormat(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getSamples() const
+{
+	return 0;
+}
+
+///// RenderbufferTextureCubeMap Implementation ////////
+
+RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target)
+{
+	mTextureCubeMap.set(texture);
+}
+
+RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap()
+{
+	mTextureCubeMap.set(NULL);
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy)
+{
+    mTextureCubeMap->addProxyRef(proxy);
+}
+
+void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy)
+{
+    mTextureCubeMap->releaseProxy(proxy);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTextureCubeMap::getRenderTarget()
+{
+	return mTextureCubeMap->getRenderTarget(mTarget, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTextureCubeMap::createSharedImage()
+{
+    return mTextureCubeMap->createSharedImage(mTarget, 0);
+}
+
+bool RenderbufferTextureCubeMap::isShared() const
+{
+    return mTextureCubeMap->isShared(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getWidth() const
+{
+	return mTextureCubeMap->getWidth(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getHeight() const
+{
+	return mTextureCubeMap->getHeight(mTarget, 0);
+}
+
+GLenum RenderbufferTextureCubeMap::getFormat() const
+{
+	return mTextureCubeMap->getFormat(mTarget, 0);
+}
+
+sw::Format RenderbufferTextureCubeMap::getInternalFormat() const
+{
+	return mTextureCubeMap->getInternalFormat(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getSamples() const
+{
+	return 0;
+}
+
+////// Renderbuffer Implementation //////
+
+Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id)
+{
+	ASSERT(instance != NULL);
+	mInstance = instance;
+}
+
+Renderbuffer::~Renderbuffer()
+{
+	delete mInstance;
+}
+
+// The RenderbufferInterface contained in this Renderbuffer may need to maintain
+// its own reference count, so we pass it on here.
+void Renderbuffer::addRef()
+{
+    mInstance->addProxyRef(this);
+
+    RefCountObject::addRef();
+}
+
+void Renderbuffer::release()
+{
+    mInstance->releaseProxy(this);
+
+    RefCountObject::release();
+}
+
+// Increments refcount on image.
+// caller must Release() the returned image
+Image *Renderbuffer::getRenderTarget()
+{
+	return mInstance->getRenderTarget();
+}
+
+// Increments refcount on image.
+// caller must Release() the returned image
+Image *Renderbuffer::createSharedImage()
+{
+    return mInstance->createSharedImage();
+}
+
+bool Renderbuffer::isShared() const
+{
+    return mInstance->isShared();
+}
+
+GLsizei Renderbuffer::getWidth() const
+{
+	return mInstance->getWidth();
+}
+
+GLsizei Renderbuffer::getHeight() const
+{
+	return mInstance->getHeight();
+}
+
+GLenum Renderbuffer::getFormat() const
+{
+	return mInstance->getFormat();
+}
+
+sw::Format Renderbuffer::getInternalFormat() const
+{
+	return mInstance->getInternalFormat();
+}
+
+GLuint Renderbuffer::getRedSize() const
+{
+	return mInstance->getRedSize();
+}
+
+GLuint Renderbuffer::getGreenSize() const
+{
+	return mInstance->getGreenSize();
+}
+
+GLuint Renderbuffer::getBlueSize() const
+{
+	return mInstance->getBlueSize();
+}
+
+GLuint Renderbuffer::getAlphaSize() const
+{
+	return mInstance->getAlphaSize();
+}
+
+GLuint Renderbuffer::getDepthSize() const
+{
+	return mInstance->getDepthSize();
+}
+
+GLuint Renderbuffer::getStencilSize() const
+{
+	return mInstance->getStencilSize();
+}
+
+GLsizei Renderbuffer::getSamples() const
+{
+	return mInstance->getSamples();
+}
+
+void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
+{
+	ASSERT(newStorage != NULL);
+
+	delete mInstance;
+	mInstance = newStorage;
+}
+
+RenderbufferStorage::RenderbufferStorage()
+{
+	mWidth = 0;
+	mHeight = 0;
+	format = GL_RGBA4;
+	internalFormat = sw::FORMAT_A8R8G8B8;
+	mSamples = 0;
+}
+
+RenderbufferStorage::~RenderbufferStorage()
+{
+}
+
+GLsizei RenderbufferStorage::getWidth() const
+{
+	return mWidth;
+}
+
+GLsizei RenderbufferStorage::getHeight() const
+{
+	return mHeight;
+}
+
+GLenum RenderbufferStorage::getFormat() const
+{
+	return format;
+}
+
+sw::Format RenderbufferStorage::getInternalFormat() const
+{
+	return internalFormat;
+}
+
+GLsizei RenderbufferStorage::getSamples() const
+{
+	return mSamples;
+}
+
+Colorbuffer::Colorbuffer(Image *renderTarget) : mRenderTarget(renderTarget)
+{
+	if(renderTarget)
+	{
+		renderTarget->addRef();
+		
+		mWidth = renderTarget->getWidth();
+		mHeight = renderTarget->getHeight();
+		internalFormat = renderTarget->getInternalFormat();
+		format = sw2es::ConvertBackBufferFormat(internalFormat);
+		mSamples = renderTarget->getMultiSampleDepth() & ~1;
+	}
+}
+
+Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL)
+{
+	Device *device = getDevice();
+
+	sw::Format requestedFormat = es2sw::ConvertRenderbufferFormat(format);
+	int supportedSamples = Context::getSupportedMultiSampleDepth(requestedFormat, samples);
+
+	if(width > 0 && height > 0)
+	{
+		mRenderTarget = device->createRenderTarget(width, height, requestedFormat, supportedSamples, false);
+
+		if(!mRenderTarget)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+	}
+
+	mWidth = width;
+	mHeight = height;
+	this->format = format;
+	internalFormat = requestedFormat;
+	mSamples = supportedSamples & ~1;
+}
+
+Colorbuffer::~Colorbuffer()
+{
+	if(mRenderTarget)
+	{
+		mRenderTarget->release();
+	}
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *Colorbuffer::getRenderTarget()
+{
+	if(mRenderTarget)
+	{
+		mRenderTarget->addRef();
+	}
+
+	return mRenderTarget;
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *Colorbuffer::createSharedImage()
+{
+    if(mRenderTarget)
+    {
+        mRenderTarget->addRef();
+        mRenderTarget->markShared();
+    }
+
+    return mRenderTarget;
+}
+
+bool Colorbuffer::isShared() const
+{
+    return mRenderTarget->isShared();
+}
+
+DepthStencilbuffer::DepthStencilbuffer(Image *depthStencil) : mDepthStencil(depthStencil)
+{
+	if(depthStencil)
+	{
+		depthStencil->addRef();
+
+		mWidth = depthStencil->getWidth();
+		mHeight = depthStencil->getHeight();
+		internalFormat = depthStencil->getInternalFormat();
+		format = sw2es::ConvertDepthStencilFormat(internalFormat);
+		mSamples = depthStencil->getMultiSampleDepth() & ~1;
+	}
+}
+
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples)
+{
+	Device *device = getDevice();
+
+	mDepthStencil = NULL;
+	
+	int supportedSamples = Context::getSupportedMultiSampleDepth(sw::FORMAT_D24S8, samples);
+
+	if(width > 0 && height > 0)
+	{
+		mDepthStencil = device->createDepthStencilSurface(width, height, sw::FORMAT_D24S8, supportedSamples, false);
+
+		if(!mDepthStencil)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+	}
+
+	mWidth = width;
+	mHeight = height;
+	format = GL_DEPTH24_STENCIL8_OES;
+	internalFormat = sw::FORMAT_D24S8;
+	mSamples = supportedSamples & ~1;
+}
+
+DepthStencilbuffer::~DepthStencilbuffer()
+{
+	if(mDepthStencil)
+	{
+		mDepthStencil->release();
+	}
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *DepthStencilbuffer::getRenderTarget()
+{
+	if(mDepthStencil)
+	{
+		mDepthStencil->addRef();
+	}
+
+	return mDepthStencil;
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *DepthStencilbuffer::createSharedImage()
+{
+    if(mDepthStencil)
+    {
+        mDepthStencil->addRef();
+        mDepthStencil->markShared();
+    }
+
+    return mDepthStencil;
+}
+
+bool DepthStencilbuffer::isShared() const
+{
+    return mDepthStencil->isShared();
+}
+
+Depthbuffer::Depthbuffer(Image *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+	if(depthStencil)
+	{
+		format = GL_DEPTH_COMPONENT16;   // If the renderbuffer parameters are queried, the calling function
+		                                 // will expect one of the valid renderbuffer formats for use in 
+		                                 // glRenderbufferStorage
+	}
+}
+
+Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+{
+	if(mDepthStencil)
+	{
+		format = GL_DEPTH_COMPONENT16;   // If the renderbuffer parameters are queried, the calling function
+		                                 // will expect one of the valid renderbuffer formats for use in 
+		                                 // glRenderbufferStorage
+	}
+}
+
+Depthbuffer::~Depthbuffer()
+{
+}
+
+Stencilbuffer::Stencilbuffer(Image *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+	if(depthStencil)
+	{
+		format = GL_STENCIL_INDEX8;   // If the renderbuffer parameters are queried, the calling function
+		                              // will expect one of the valid renderbuffer formats for use in 
+		                              // glRenderbufferStorage
+	}
+}
+
+Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+{
+	if(mDepthStencil)
+	{
+		format = GL_STENCIL_INDEX8;   // If the renderbuffer parameters are queried, the calling function
+		                              // will expect one of the valid renderbuffer formats for use in 
+		                              // glRenderbufferStorage
+	}
+}
+
+Stencilbuffer::~Stencilbuffer()
+{
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Renderbuffer.h b/src/GLES2/libGLES_CM/Renderbuffer.h
new file mode 100644
index 0000000..2e8a49e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Renderbuffer.h
@@ -0,0 +1,229 @@
+// 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.

+//

+

+// Renderbuffer.h: Defines the wrapper class Renderbuffer, as well as the

+// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer,

+// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer

+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.

+

+#ifndef LIBGLESV2_RENDERBUFFER_H_

+#define LIBGLESV2_RENDERBUFFER_H_

+

+#include "RefCountObject.h"

+#include "Image.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+class Texture2D;

+class TextureCubeMap;

+class Renderbuffer;

+class Colorbuffer;

+class DepthStencilbuffer;

+

+class RenderbufferInterface

+{

+public:

+	RenderbufferInterface();

+

+	virtual ~RenderbufferInterface() {};

+

+	virtual void addProxyRef(const Renderbuffer *proxy);

+    virtual void releaseProxy(const Renderbuffer *proxy);

+

+	virtual Image *getRenderTarget() = 0;

+    virtual Image *createSharedImage() = 0;

+    virtual bool isShared() const = 0;

+

+	virtual GLsizei getWidth() const = 0;

+	virtual GLsizei getHeight() const = 0;

+	virtual GLenum getFormat() const = 0;

+	virtual sw::Format getInternalFormat() const = 0;

+	virtual GLsizei getSamples() const = 0;

+

+	GLuint getRedSize() const;

+	GLuint getGreenSize() const;

+	GLuint getBlueSize() const;

+	GLuint getAlphaSize() const;

+	GLuint getDepthSize() const;

+	GLuint getStencilSize() const;

+};

+

+class RenderbufferTexture2D : public RenderbufferInterface

+{

+public:

+	RenderbufferTexture2D(Texture2D *texture);

+

+	virtual ~RenderbufferTexture2D();

+

+	virtual void addProxyRef(const Renderbuffer *proxy);

+    virtual void releaseProxy(const Renderbuffer *proxy);

+

+	virtual Image *getRenderTarget();

+    virtual Image *createSharedImage();

+    virtual bool isShared() const;

+

+	virtual GLsizei getWidth() const;

+	virtual GLsizei getHeight() const;

+	virtual GLenum getFormat() const;

+	virtual sw::Format getInternalFormat() const;

+	virtual GLsizei getSamples() const;

+

+private:

+	BindingPointer<Texture2D> mTexture2D;

+};

+

+class RenderbufferTextureCubeMap : public RenderbufferInterface

+{

+public:

+	RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target);

+

+	virtual ~RenderbufferTextureCubeMap();

+

+	virtual void addProxyRef(const Renderbuffer *proxy);

+    virtual void releaseProxy(const Renderbuffer *proxy);

+

+	virtual Image *getRenderTarget();

+    virtual Image *createSharedImage();

+    virtual bool isShared() const;

+

+	virtual GLsizei getWidth() const;

+	virtual GLsizei getHeight() const;

+	virtual GLenum getFormat() const;

+	virtual sw::Format getInternalFormat() const;

+	virtual GLsizei getSamples() const;

+

+private:

+	BindingPointer<TextureCubeMap> mTextureCubeMap;

+	GLenum mTarget;

+};

+

+// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage

+// is called. The specific concrete type depends on whether the internal format is

+// colour depth, stencil or packed depth/stencil.

+class RenderbufferStorage : public RenderbufferInterface

+{

+public:

+	RenderbufferStorage();

+

+	virtual ~RenderbufferStorage() = 0;

+

+	virtual Image *getRenderTarget() = 0;

+    virtual Image *createSharedImage() = 0;

+    virtual bool isShared() const = 0;

+

+	virtual GLsizei getWidth() const;

+	virtual GLsizei getHeight() const;

+	virtual GLenum getFormat() const;

+	virtual sw::Format getInternalFormat() const;

+	virtual GLsizei getSamples() const;

+

+protected:

+	GLsizei mWidth;

+	GLsizei mHeight;

+	GLenum format;

+	sw::Format internalFormat;

+	GLsizei mSamples;

+};

+

+// Renderbuffer implements the GL renderbuffer object.

+// It's only a proxy for a RenderbufferInterface instance; the internal object

+// can change whenever glRenderbufferStorage is called.

+class Renderbuffer : public RefCountObject

+{

+public:

+	Renderbuffer(GLuint id, RenderbufferInterface *storage);

+

+	virtual ~Renderbuffer();

+

+	// These functions from RefCountObject are overloaded here because

+    // Textures need to maintain their own count of references to them via

+    // Renderbuffers/RenderbufferTextures. These functions invoke those

+    // reference counting functions on the RenderbufferInterface.

+    virtual void addRef();

+    virtual void release();

+

+	Image *getRenderTarget();

+    virtual Image *createSharedImage();

+    virtual bool isShared() const;

+

+	GLsizei getWidth() const;

+	GLsizei getHeight() const;

+	GLenum getFormat() const;

+	sw::Format getInternalFormat() const;

+	GLuint getRedSize() const;

+	GLuint getGreenSize() const;

+	GLuint getBlueSize() const;

+	GLuint getAlphaSize() const;

+	GLuint getDepthSize() const;

+	GLuint getStencilSize() const;

+	GLsizei getSamples() const;

+

+	void setStorage(RenderbufferStorage *newStorage);

+

+private:

+	RenderbufferInterface *mInstance;

+};

+

+class Colorbuffer : public RenderbufferStorage

+{

+public:

+	explicit Colorbuffer(Image *renderTarget);

+	Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);

+

+	virtual ~Colorbuffer();

+

+	virtual Image *getRenderTarget();

+    virtual Image *createSharedImage();

+    virtual bool isShared() const;

+

+private:

+	Image *mRenderTarget;

+};

+

+class DepthStencilbuffer : public RenderbufferStorage

+{

+public:

+	explicit DepthStencilbuffer(Image *depthStencil);

+	DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);

+

+	~DepthStencilbuffer();

+

+	virtual Image *getRenderTarget();

+    virtual Image *createSharedImage();

+    virtual bool isShared() const;

+

+protected:

+	Image *mDepthStencil;

+};

+

+class Depthbuffer : public DepthStencilbuffer

+{

+public:

+	explicit Depthbuffer(Image *depthStencil);

+	Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);

+

+	virtual ~Depthbuffer();

+};

+

+class Stencilbuffer : public DepthStencilbuffer

+{

+public:

+	explicit Stencilbuffer(Image *depthStencil);

+	Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);

+

+	virtual ~Stencilbuffer();

+};

+}

+

+#endif   // LIBGLESV2_RENDERBUFFER_H_

diff --git a/src/GLES2/libGLES_CM/ResourceManager.cpp b/src/GLES2/libGLES_CM/ResourceManager.cpp
new file mode 100644
index 0000000..8bddcc8
--- /dev/null
+++ b/src/GLES2/libGLES_CM/ResourceManager.cpp
@@ -0,0 +1,329 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// ResourceManager.cpp: Implements the ResourceManager class, which tracks and 
+// retrieves objects which may be shared by multiple Contexts.
+
+#include "ResourceManager.h"
+
+#include "Buffer.h"
+#include "Program.h"
+#include "Renderbuffer.h"
+#include "Shader.h"
+#include "Texture.h"
+
+namespace gl
+{
+ResourceManager::ResourceManager()
+{
+    mRefCount = 1;
+}
+
+ResourceManager::~ResourceManager()
+{
+    while(!mBufferMap.empty())
+    {
+        deleteBuffer(mBufferMap.begin()->first);
+    }
+
+    while(!mProgramMap.empty())
+    {
+        deleteProgram(mProgramMap.begin()->first);
+    }
+
+    while(!mShaderMap.empty())
+    {
+        deleteShader(mShaderMap.begin()->first);
+    }
+
+    while(!mRenderbufferMap.empty())
+    {
+        deleteRenderbuffer(mRenderbufferMap.begin()->first);
+    }
+
+    while(!mTextureMap.empty())
+    {
+        deleteTexture(mTextureMap.begin()->first);
+    }
+}
+
+void ResourceManager::addRef()
+{
+    mRefCount++;
+}
+
+void ResourceManager::release()
+{
+    if(--mRefCount == 0)
+    {
+        delete this;
+    }
+}
+
+// Returns an unused buffer name
+GLuint ResourceManager::createBuffer()
+{
+    GLuint handle = mBufferHandleAllocator.allocate();
+
+    mBufferMap[handle] = NULL;
+
+    return handle;
+}
+
+// Returns an unused shader/program name
+GLuint ResourceManager::createShader(GLenum type)
+{
+    GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+    if(type == GL_VERTEX_SHADER)
+    {
+        mShaderMap[handle] = new VertexShader(this, handle);
+    }
+    else if(type == GL_FRAGMENT_SHADER)
+    {
+        mShaderMap[handle] = new FragmentShader(this, handle);
+    }
+    else UNREACHABLE();
+
+    return handle;
+}
+
+// Returns an unused program/shader name
+GLuint ResourceManager::createProgram()
+{
+    GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+    mProgramMap[handle] = new Program(this, handle);
+
+    return handle;
+}
+
+// Returns an unused texture name
+GLuint ResourceManager::createTexture()
+{
+    GLuint handle = mTextureHandleAllocator.allocate();
+
+    mTextureMap[handle] = NULL;
+
+    return handle;
+}
+
+// Returns an unused renderbuffer name
+GLuint ResourceManager::createRenderbuffer()
+{
+    GLuint handle = mRenderbufferHandleAllocator.allocate();
+
+    mRenderbufferMap[handle] = NULL;
+
+    return handle;
+}
+
+void ResourceManager::deleteBuffer(GLuint buffer)
+{
+    BufferMap::iterator bufferObject = mBufferMap.find(buffer);
+
+    if(bufferObject != mBufferMap.end())
+    {
+        mBufferHandleAllocator.release(bufferObject->first);
+        if(bufferObject->second) bufferObject->second->release();
+        mBufferMap.erase(bufferObject);
+    }
+}
+
+void ResourceManager::deleteShader(GLuint shader)
+{
+    ShaderMap::iterator shaderObject = mShaderMap.find(shader);
+
+    if(shaderObject != mShaderMap.end())
+    {
+        if(shaderObject->second->getRefCount() == 0)
+        {
+            mProgramShaderHandleAllocator.release(shaderObject->first);
+            delete shaderObject->second;
+            mShaderMap.erase(shaderObject);
+        }
+        else
+        {
+            shaderObject->second->flagForDeletion();
+        }
+    }
+}
+
+void ResourceManager::deleteProgram(GLuint program)
+{
+    ProgramMap::iterator programObject = mProgramMap.find(program);
+
+    if(programObject != mProgramMap.end())
+    {
+        if(programObject->second->getRefCount() == 0)
+        {
+            mProgramShaderHandleAllocator.release(programObject->first);
+            delete programObject->second;
+            mProgramMap.erase(programObject);
+        }
+        else
+        { 
+            programObject->second->flagForDeletion();
+        }
+    }
+}
+
+void ResourceManager::deleteTexture(GLuint texture)
+{
+    TextureMap::iterator textureObject = mTextureMap.find(texture);
+
+    if(textureObject != mTextureMap.end())
+    {
+        mTextureHandleAllocator.release(textureObject->first);
+        if(textureObject->second) textureObject->second->release();
+        mTextureMap.erase(textureObject);
+    }
+}
+
+void ResourceManager::deleteRenderbuffer(GLuint renderbuffer)
+{
+    RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer);
+
+    if(renderbufferObject != mRenderbufferMap.end())
+    {
+        mRenderbufferHandleAllocator.release(renderbufferObject->first);
+        if(renderbufferObject->second) renderbufferObject->second->release();
+        mRenderbufferMap.erase(renderbufferObject);
+    }
+}
+
+Buffer *ResourceManager::getBuffer(unsigned int handle)
+{
+    BufferMap::iterator buffer = mBufferMap.find(handle);
+
+    if(buffer == mBufferMap.end())
+    {
+        return NULL;
+    }
+    else
+    {
+        return buffer->second;
+    }
+}
+
+Shader *ResourceManager::getShader(unsigned int handle)
+{
+    ShaderMap::iterator shader = mShaderMap.find(handle);
+
+    if(shader == mShaderMap.end())
+    {
+        return NULL;
+    }
+    else
+    {
+        return shader->second;
+    }
+}
+
+Texture *ResourceManager::getTexture(unsigned int handle)
+{
+    if(handle == 0) return NULL;
+
+    TextureMap::iterator texture = mTextureMap.find(handle);
+
+    if(texture == mTextureMap.end())
+    {
+        return NULL;
+    }
+    else
+    {
+        return texture->second;
+    }
+}
+
+Program *ResourceManager::getProgram(unsigned int handle)
+{
+    ProgramMap::iterator program = mProgramMap.find(handle);
+
+    if(program == mProgramMap.end())
+    {
+        return NULL;
+    }
+    else
+    {
+        return program->second;
+    }
+}
+
+Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle)
+{
+    RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle);
+
+    if(renderbuffer == mRenderbufferMap.end())
+    {
+        return NULL;
+    }
+    else
+    {
+        return renderbuffer->second;
+    }
+}
+
+void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer)
+{
+    mRenderbufferMap[handle] = buffer;
+}
+
+void ResourceManager::checkBufferAllocation(unsigned int buffer)
+{
+    if(buffer != 0 && !getBuffer(buffer))
+    {
+        Buffer *bufferObject = new Buffer(buffer);
+        mBufferMap[buffer] = bufferObject;
+        bufferObject->addRef();
+    }
+}
+
+void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type)
+{
+    if(!getTexture(texture) && texture != 0)
+    {
+        Texture *textureObject;
+
+        if(type == TEXTURE_2D)
+        {
+            textureObject = new Texture2D(texture);
+        }
+        else if(type == TEXTURE_CUBE)
+        {
+            textureObject = new TextureCubeMap(texture);
+        }
+        else if(type == TEXTURE_EXTERNAL)
+        {
+            textureObject = new TextureExternal(texture);
+        }
+        else
+        {
+            UNREACHABLE();
+            return;
+        }
+
+        mTextureMap[texture] = textureObject;
+        textureObject->addRef();
+    }
+}
+
+void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer)
+{
+    if(renderbuffer != 0 && !getRenderbuffer(renderbuffer))
+    {
+        Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(0, 0, GL_RGBA4, 0));
+        mRenderbufferMap[renderbuffer] = renderbufferObject;
+        renderbufferObject->addRef();
+    }
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/ResourceManager.h b/src/GLES2/libGLES_CM/ResourceManager.h
new file mode 100644
index 0000000..cd4ae12
--- /dev/null
+++ b/src/GLES2/libGLES_CM/ResourceManager.h
@@ -0,0 +1,101 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// ResourceManager.h : Defines the ResourceManager class, which tracks objects

+// shared by multiple GL contexts.

+

+#ifndef LIBGLESV2_RESOURCEMANAGER_H_

+#define LIBGLESV2_RESOURCEMANAGER_H_

+

+#include "HandleAllocator.h"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+#include <map>

+

+namespace gl

+{

+class Buffer;

+class Shader;

+class Program;

+class Texture;

+class Renderbuffer;

+

+enum TextureType

+{

+    TEXTURE_2D,

+    TEXTURE_CUBE,

+    TEXTURE_EXTERNAL,

+

+    TEXTURE_TYPE_COUNT,

+    TEXTURE_UNKNOWN

+};

+

+class ResourceManager

+{

+  public:

+    ResourceManager();

+    ~ResourceManager();

+

+    void addRef();

+    void release();

+

+    GLuint createBuffer();

+    GLuint createShader(GLenum type);

+    GLuint createProgram();

+    GLuint createTexture();

+    GLuint createRenderbuffer();

+

+    void deleteBuffer(GLuint buffer);

+    void deleteShader(GLuint shader);

+    void deleteProgram(GLuint program);

+    void deleteTexture(GLuint texture);

+    void deleteRenderbuffer(GLuint renderbuffer);

+

+    Buffer *getBuffer(GLuint handle);

+    Shader *getShader(GLuint handle);

+    Program *getProgram(GLuint handle);

+    Texture *getTexture(GLuint handle);

+    Renderbuffer *getRenderbuffer(GLuint handle);

+    

+    void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer);

+

+    void checkBufferAllocation(unsigned int buffer);

+    void checkTextureAllocation(GLuint texture, TextureType type);

+    void checkRenderbufferAllocation(GLuint renderbuffer);

+

+  private:

+    std::size_t mRefCount;

+

+    typedef std::map<GLint, Buffer*> BufferMap;

+    BufferMap mBufferMap;

+    HandleAllocator mBufferHandleAllocator;

+

+    typedef std::map<GLint, Shader*> ShaderMap;

+    ShaderMap mShaderMap;

+

+    typedef std::map<GLint, Program*> ProgramMap;

+    ProgramMap mProgramMap;

+    HandleAllocator mProgramShaderHandleAllocator;

+

+    typedef std::map<GLint, Texture*> TextureMap;

+    TextureMap mTextureMap;

+    HandleAllocator mTextureHandleAllocator;

+

+    typedef std::map<GLint, Renderbuffer*> RenderbufferMap;

+    RenderbufferMap mRenderbufferMap;

+    HandleAllocator mRenderbufferHandleAllocator;

+};

+

+}

+

+#endif // LIBGLESV2_RESOURCEMANAGER_H_

diff --git a/src/GLES2/libGLES_CM/Shader.cpp b/src/GLES2/libGLES_CM/Shader.cpp
new file mode 100644
index 0000000..e4cb5ee
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Shader.cpp
@@ -0,0 +1,511 @@
+// 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.
+//
+
+// Shader.cpp: Implements the Shader class and its  derived classes
+// VertexShader and FragmentShader. Implements GL shader objects and related
+// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
+
+#include "Shader.h"
+
+#include "main.h"
+#include "utilities.h"
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <string>
+
+namespace gl
+{
+Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
+{
+    mSource = NULL;
+    mInfoLog = NULL;
+
+	clear();
+
+    mRefCount = 0;
+    mDeleteStatus = false;
+}
+
+Shader::~Shader()
+{
+    delete[] mSource;
+    delete[] mInfoLog;
+}
+
+GLuint Shader::getHandle() const
+{
+    return mHandle;
+}
+
+void Shader::setSource(GLsizei count, const char **string, const GLint *length)
+{
+    delete[] mSource;
+    int totalLength = 0;
+
+    for(int i = 0; i < count; i++)
+    {
+        if(length && length[i] >= 0)
+        {
+            totalLength += length[i];
+        }
+        else
+        {
+            totalLength += (int)strlen(string[i]);
+        }
+    }
+
+    mSource = new char[totalLength + 1];
+    char *code = mSource;
+
+    for(int i = 0; i < count; i++)
+    {
+        int stringLength;
+
+        if(length && length[i] >= 0)
+        {
+            stringLength = length[i];
+        }
+        else
+        {
+            stringLength = (int)strlen(string[i]);
+        }
+
+        strncpy(code, string[i], stringLength);
+        code += stringLength;
+    }
+
+    mSource[totalLength] = '\0';
+}
+
+int Shader::getInfoLogLength() const
+{
+    if(!mInfoLog)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mInfoLog) + 1;
+    }
+}
+
+void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+    int index = 0;
+
+	if(bufSize > 0)
+	{
+		if(mInfoLog)
+		{
+			index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+			memcpy(infoLog, mInfoLog, index);
+		}
+
+        infoLog[index] = '\0';
+    }
+
+    if(length)
+    {
+        *length = index;
+    }
+}
+
+int Shader::getSourceLength() const
+{
+    if(!mSource)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mSource) + 1;
+    }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
+{
+    int index = 0;
+
+	if(bufSize > 0)
+	{
+		if(mSource)
+		{
+			index = std::min(bufSize - 1, (int)strlen(mSource));
+			memcpy(source, mSource, index);
+		}
+
+        source[index] = '\0';
+    }
+
+    if(length)
+    {
+        *length = index;
+    }
+}
+
+TranslatorASM *Shader::createCompiler(ShShaderType type)
+{
+	ShInitialize();
+
+	TranslatorASM *assembler = new TranslatorASM(this, type, SH_GLES2_SPEC);
+
+	ShBuiltInResources resources;
+	ShInitBuiltInResources(&resources);     
+	resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
+	resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
+	resources.MaxVaryingVectors = MAX_VARYING_VECTORS;
+	resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+	resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+	resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+	resources.MaxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
+	resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+	resources.OES_standard_derivatives = 1;
+	resources.OES_fragment_precision_high = 1;
+	resources.MaxCallStackDepth = 16;
+	assembler->Init(resources);
+
+	return assembler;
+}
+
+void Shader::clear()
+{
+    delete[] mInfoLog;
+    mInfoLog = NULL;
+
+    varyings.clear();
+	activeAttributes.clear();
+}
+
+bool Shader::isCompiled()
+{
+    return getShader() != 0;
+}
+
+sw::PixelShader *Shader::getPixelShader() const
+{
+	return 0;
+}
+
+sw::VertexShader *Shader::getVertexShader() const
+{
+	return 0;
+}
+
+void Shader::addRef()
+{
+    mRefCount++;
+}
+
+void Shader::release()
+{
+    mRefCount--;
+
+    if(mRefCount == 0 && mDeleteStatus)
+    {
+        mResourceManager->deleteShader(mHandle);
+    }
+}
+
+unsigned int Shader::getRefCount() const
+{
+    return mRefCount;
+}
+
+bool Shader::isFlaggedForDeletion() const
+{
+    return mDeleteStatus;
+}
+
+void Shader::flagForDeletion()
+{
+    mDeleteStatus = true;
+}
+
+void Shader::releaseCompiler()
+{
+    ShFinalize();
+}
+
+GLenum Shader::parseType(const std::string &type)
+{
+    if(type == "float")
+    {
+        return GL_FLOAT;
+    }
+    else if(type == "float2")
+    {
+        return GL_FLOAT_VEC2;
+    }
+    else if(type == "float3")
+    {
+        return GL_FLOAT_VEC3;
+    }
+    else if(type == "float4")
+    {
+        return GL_FLOAT_VEC4;
+    }
+    else if(type == "float2x2")
+    {
+        return GL_FLOAT_MAT2;
+    }
+    else if(type == "float3x3")
+    {
+        return GL_FLOAT_MAT3;
+    }
+    else if(type == "float4x4")
+    {
+        return GL_FLOAT_MAT4;
+    }
+    else UNREACHABLE();
+
+    return GL_NONE;
+}
+
+// true if varying x has a higher priority in packing than y
+bool Shader::compareVarying(const Varying &x, const Varying &y)
+{
+    if(x.type == y.type)
+    {
+        return x.size() > y.size();
+    }
+
+    switch (x.type)
+    {
+      case GL_FLOAT_MAT4: return true;
+      case GL_FLOAT_MAT2:
+        switch(y.type)
+        {
+          case GL_FLOAT_MAT4: return false;
+          case GL_FLOAT_MAT2: return true;
+          case GL_FLOAT_VEC4: return true;
+          case GL_FLOAT_MAT3: return true;
+          case GL_FLOAT_VEC3: return true;
+          case GL_FLOAT_VEC2: return true;
+          case GL_FLOAT:      return true;
+          default: UNREACHABLE();
+        }
+        break;
+      case GL_FLOAT_VEC4:
+        switch(y.type)
+        {
+          case GL_FLOAT_MAT4: return false;
+          case GL_FLOAT_MAT2: return false;
+          case GL_FLOAT_VEC4: return true;
+          case GL_FLOAT_MAT3: return true;
+          case GL_FLOAT_VEC3: return true;
+          case GL_FLOAT_VEC2: return true;
+          case GL_FLOAT:      return true;
+          default: UNREACHABLE();
+        }
+        break;
+      case GL_FLOAT_MAT3:
+        switch(y.type)
+        {
+          case GL_FLOAT_MAT4: return false;
+          case GL_FLOAT_MAT2: return false;
+          case GL_FLOAT_VEC4: return false;
+          case GL_FLOAT_MAT3: return true;
+          case GL_FLOAT_VEC3: return true;
+          case GL_FLOAT_VEC2: return true;
+          case GL_FLOAT:      return true;
+          default: UNREACHABLE();
+        }
+        break;
+      case GL_FLOAT_VEC3:
+        switch(y.type)
+        {
+          case GL_FLOAT_MAT4: return false;
+          case GL_FLOAT_MAT2: return false;
+          case GL_FLOAT_VEC4: return false;
+          case GL_FLOAT_MAT3: return false;
+          case GL_FLOAT_VEC3: return true;
+          case GL_FLOAT_VEC2: return true;
+          case GL_FLOAT:      return true;
+          default: UNREACHABLE();
+        }
+        break;
+      case GL_FLOAT_VEC2:
+        switch(y.type)
+        {
+          case GL_FLOAT_MAT4: return false;
+          case GL_FLOAT_MAT2: return false;
+          case GL_FLOAT_VEC4: return false;
+          case GL_FLOAT_MAT3: return false;
+          case GL_FLOAT_VEC3: return false;
+          case GL_FLOAT_VEC2: return true;
+          case GL_FLOAT:      return true;
+          default: UNREACHABLE();
+        }
+        break;
+      case GL_FLOAT: return false;
+      default: UNREACHABLE();
+    }
+
+    return false;
+}
+
+VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+	vertexShader = 0;
+}
+
+VertexShader::~VertexShader()
+{
+	delete vertexShader;
+}
+
+GLenum VertexShader::getType()
+{
+    return GL_VERTEX_SHADER;
+}
+
+void VertexShader::compile()
+{
+	clear();
+
+	delete vertexShader;
+	vertexShader = new sw::VertexShader();
+
+	TranslatorASM *compiler = createCompiler(SH_VERTEX_SHADER);
+
+	// Ensure we don't pass a NULL source to the compiler
+    char *source = "\0";
+	if(mSource)
+    {
+        source = mSource;
+    }
+
+	int success = ShCompile(compiler, &source, 1, SH_OBJECT_CODE);
+
+	if(false)
+	{
+		static int serial = 1;
+		char buffer[256];
+		sprintf(buffer, "vertex-input-%d-%d.txt", getHandle(), serial);
+		FILE *file = fopen(buffer, "wt");
+		fprintf(file, mSource);
+		fclose(file);
+		vertexShader->print("vertex-output-%d-%d.txt", getHandle(), serial);
+		serial++;
+	}
+
+	if(!success)
+	{
+		delete vertexShader;
+		vertexShader = 0;
+
+		int infoLogLen = 0;
+        ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+        mInfoLog = new char[infoLogLen];
+        ShGetInfoLog(compiler, mInfoLog);
+        TRACE("\n%s", mInfoLog);
+	}
+
+	delete compiler;
+}
+
+int VertexShader::getSemanticIndex(const std::string &attributeName)
+{
+    if(!attributeName.empty())
+    {
+		for(sh::ActiveAttributes::iterator attribute = activeAttributes.begin(); attribute != activeAttributes.end(); attribute++)
+        {
+            if(attribute->name == attributeName)
+            {
+				return attribute->registerIndex;
+            }
+        }
+    }
+
+    return -1;
+}
+
+sw::Shader *VertexShader::getShader() const
+{
+	return vertexShader;
+}
+
+sw::VertexShader *VertexShader::getVertexShader() const
+{
+	return vertexShader;
+}
+
+FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+	pixelShader = 0;
+}
+
+FragmentShader::~FragmentShader()
+{
+	delete pixelShader;
+}
+
+GLenum FragmentShader::getType()
+{
+    return GL_FRAGMENT_SHADER;
+}
+
+void FragmentShader::compile()
+{
+	clear();
+
+	delete pixelShader;
+	pixelShader = new sw::PixelShader();
+
+	TranslatorASM *compiler = createCompiler(SH_FRAGMENT_SHADER);
+
+	// Ensure we don't pass a NULL source to the compiler
+    char *source = "\0";
+	if(mSource)
+    {
+        source = mSource;
+    }
+
+	int success = ShCompile(compiler, &source, 1, SH_OBJECT_CODE);
+	
+	if(false)
+	{
+		static int serial = 1;
+		char buffer[256];
+		sprintf(buffer, "pixel-input-%d-%d.txt", getHandle(), serial);
+		FILE *file = fopen(buffer, "wt");
+		fprintf(file, mSource);
+		fclose(file);
+		pixelShader->print("pixel-output-%d-%d.txt", getHandle(), serial);
+		serial++;
+	}
+
+	if(!success)
+	{
+		delete pixelShader;
+		pixelShader = 0;
+
+		int infoLogLen = 0;
+        ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+        mInfoLog = new char[infoLogLen];
+        ShGetInfoLog(compiler, mInfoLog);
+        TRACE("\n%s", mInfoLog);
+	}
+
+	delete compiler;
+}
+
+sw::Shader *FragmentShader::getShader() const
+{
+	return pixelShader;
+}
+
+sw::PixelShader *FragmentShader::getPixelShader() const
+{
+	return pixelShader;
+}
+}
diff --git a/src/GLES2/libGLES_CM/Shader.h b/src/GLES2/libGLES_CM/Shader.h
new file mode 100644
index 0000000..b6e7e70
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Shader.h
@@ -0,0 +1,159 @@
+// 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.

+//

+

+// Shader.h: Defines the abstract Shader class and its concrete derived

+// classes VertexShader and FragmentShader. Implements GL shader objects and

+// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section

+// 3.8 page 84.

+

+#ifndef LIBGLESV2_SHADER_H_

+#define LIBGLESV2_SHADER_H_

+

+#include "ResourceManager.h"

+

+#include "compiler/TranslatorASM.h"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+#include <list>

+#include <vector>

+

+namespace sh

+{

+	class OutputASM;

+}

+

+namespace gl

+{

+struct Varying

+{

+    Varying(GLenum type, const std::string &name, int arraySize, int reg = -1, int col = -1)

+        : type(type), name(name), arraySize(arraySize), reg(reg), col(col)

+    {

+    }

+

+	bool isArray() const

+	{

+		return arraySize >= 1;

+	}

+

+	int size() const   // Unify with gl::Uniform?

+	{

+		return arraySize > 0 ? arraySize : 1;

+	}

+

+    GLenum type;

+    std::string name;

+    int arraySize;

+

+    int reg;    // First varying register, assigned during link

+    int col;    // First register element, assigned during link

+};

+

+typedef std::list<Varying> VaryingList;

+

+class Shader

+{

+    friend class Program;

+	friend class sh::OutputASM;

+

+public:

+    Shader(ResourceManager *manager, GLuint handle);

+

+    virtual ~Shader();

+

+    virtual GLenum getType() = 0;

+    GLuint getHandle() const;

+

+    void deleteSource();

+    void setSource(GLsizei count, const char **string, const GLint *length);

+    int getInfoLogLength() const;

+    void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);

+    int getSourceLength() const;

+    void getSource(GLsizei bufSize, GLsizei *length, char *source);

+

+    virtual void compile() = 0;

+    bool isCompiled();

+    

+	virtual sw::Shader *getShader() const = 0;

+	virtual sw::PixelShader *getPixelShader() const;

+	virtual sw::VertexShader *getVertexShader() const;

+

+    void addRef();

+    void release();

+    unsigned int getRefCount() const;

+    bool isFlaggedForDeletion() const;

+    void flagForDeletion();

+

+    static void releaseCompiler();

+

+protected:

+	TranslatorASM *createCompiler(ShShaderType type);

+	void clear();

+

+    static GLenum parseType(const std::string &type);

+    static bool compareVarying(const Varying &x, const Varying &y);

+

+	char *mSource;

+	char *mInfoLog;

+

+    VaryingList varyings;

+	sh::ActiveUniforms activeUniforms;

+	sh::ActiveAttributes activeAttributes;

+

+private:

+	const GLuint mHandle;

+    unsigned int mRefCount;     // Number of program objects this shader is attached to

+    bool mDeleteStatus;         // Flag to indicate that the shader can be deleted when no longer in use

+

+	ResourceManager *mResourceManager;

+};

+

+class VertexShader : public Shader

+{

+    friend class Program;

+

+public:

+    VertexShader(ResourceManager *manager, GLuint handle);

+

+    ~VertexShader();

+

+    virtual GLenum getType();

+    virtual void compile();

+    int getSemanticIndex(const std::string &attributeName);

+

+	virtual sw::Shader *getShader() const;

+	virtual sw::VertexShader *getVertexShader() const;

+

+private:

+	sw::VertexShader *vertexShader;

+};

+

+class FragmentShader : public Shader

+{

+public:

+    FragmentShader(ResourceManager *manager, GLuint handle);

+

+    ~FragmentShader();

+

+    virtual GLenum getType();

+    virtual void compile();

+

+	virtual sw::Shader *getShader() const;

+	virtual sw::PixelShader *getPixelShader() const;

+

+private:

+	sw::PixelShader *pixelShader;

+};

+}

+

+#endif   // LIBGLESV2_SHADER_H_

diff --git a/src/GLES2/libGLES_CM/Texture.cpp b/src/GLES2/libGLES_CM/Texture.cpp
new file mode 100644
index 0000000..25dbdb1
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Texture.cpp
@@ -0,0 +1,1167 @@
+// 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.

+//

+

+// Texture.cpp: Implements the Texture class and its derived classes

+// Texture2D and TextureCubeMap. Implements GL texture objects and related

+// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.

+

+#include "Texture.h"

+

+#include "main.h"

+#include "mathutil.h"

+#include "Framebuffer.h"

+#include "Device.hpp"

+#include "libEGL/Display.h"

+#include "common/debug.h"

+

+#include <algorithm>

+

+namespace gl

+{

+

+Texture::Texture(GLuint id) : RefCountObject(id)

+{

+    mMinFilter = GL_NEAREST_MIPMAP_LINEAR;

+    mMagFilter = GL_LINEAR;

+    mWrapS = GL_REPEAT;

+    mWrapT = GL_REPEAT;

+	mMaxAnisotropy = 1.0f;

+

+	resource = new sw::Resource(0);

+}

+

+Texture::~Texture()

+{

+	resource->destruct();

+}

+

+sw::Resource *Texture::getResource() const

+{

+	return resource;

+}

+

+// Returns true on successful filter state update (valid enum parameter)

+bool Texture::setMinFilter(GLenum filter)

+{

+    switch(filter)

+    {

+    case GL_NEAREST_MIPMAP_NEAREST:

+    case GL_LINEAR_MIPMAP_NEAREST:

+    case GL_NEAREST_MIPMAP_LINEAR:

+    case GL_LINEAR_MIPMAP_LINEAR:

+        if(getTarget() == GL_TEXTURE_EXTERNAL_OES)

+        {

+            return false;

+        }

+        // Fall through

+    case GL_NEAREST:

+    case GL_LINEAR:

+        mMinFilter = filter;

+        return true;

+    default:

+        return false;

+    }

+}

+

+// Returns true on successful filter state update (valid enum parameter)

+bool Texture::setMagFilter(GLenum filter)

+{

+    switch(filter)

+    {

+    case GL_NEAREST:

+    case GL_LINEAR:

+        mMagFilter = filter;

+        return true;

+    default:

+        return false;

+    }

+}

+

+// Returns true on successful wrap state update (valid enum parameter)

+bool Texture::setWrapS(GLenum wrap)

+{

+    switch(wrap)

+    {

+    case GL_REPEAT:

+    case GL_MIRRORED_REPEAT:

+        if(getTarget() == GL_TEXTURE_EXTERNAL_OES)

+        {

+            return false;

+        }

+        // Fall through

+    case GL_CLAMP_TO_EDGE:

+        mWrapS = wrap;

+        return true;

+    default:

+        return false;

+    }

+}

+

+// Returns true on successful wrap state update (valid enum parameter)

+bool Texture::setWrapT(GLenum wrap)

+{

+    switch(wrap)

+    {

+    case GL_REPEAT:

+    case GL_MIRRORED_REPEAT:

+        if(getTarget() == GL_TEXTURE_EXTERNAL_OES)

+        {

+            return false;

+        }

+        // Fall through

+    case GL_CLAMP_TO_EDGE:

+         mWrapT = wrap;

+         return true;

+    default:

+        return false;

+    }

+}

+

+// Returns true on successful max anisotropy update (valid anisotropy value)

+bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)

+{

+    textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);

+

+    if(textureMaxAnisotropy < 1.0f)

+    {

+        return false;

+    }

+    

+	if(mMaxAnisotropy != textureMaxAnisotropy)

+    {

+        mMaxAnisotropy = textureMaxAnisotropy;

+    }

+

+    return true;

+}

+

+GLenum Texture::getMinFilter() const

+{

+    return mMinFilter;

+}

+

+GLenum Texture::getMagFilter() const

+{

+    return mMagFilter;

+}

+

+GLenum Texture::getWrapS() const

+{

+    return mWrapS;

+}

+

+GLenum Texture::getWrapT() const

+{

+    return mWrapT;

+}

+

+GLfloat Texture::getMaxAnisotropy() const

+{

+    return mMaxAnisotropy;

+}

+

+Image *Texture::createSharedImage(GLenum target, unsigned int level)

+{

+    Image *image = getRenderTarget(target, level);   // Increments reference count

+

+    if(image)

+    {

+        image->markShared();

+    }

+

+    return image;

+}

+

+void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)

+{

+    if(pixels && image)

+    {

+		image->loadImageData(0, 0, image->getWidth(), image->getHeight(), format, type, unpackAlignment, pixels);

+    }

+}

+

+void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)

+{

+    if(pixels && image)

+    {

+		image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), imageSize, pixels);

+    }

+}

+

+void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)

+{

+	if(!image)

+	{

+		return error(GL_INVALID_OPERATION);

+	}

+

+    if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    if(IsCompressed(image->getFormat()))

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(format != image->getFormat())

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(pixels)

+    {

+        image->loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels);

+    }

+}

+

+void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)

+{

+	if(!image)

+	{

+		return error(GL_INVALID_OPERATION);

+	}

+

+    if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    if(format != image->getFormat())

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    if(pixels)

+    {

+		image->loadCompressedData(xoffset, yoffset, width, height, imageSize, pixels);

+    }

+}

+

+bool Texture::copy(Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, Image *dest)

+{

+    Device *device = getDevice();

+	

+    sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};

+    bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);

+

+    if(!success)

+    {

+        return error(GL_OUT_OF_MEMORY, false);

+    }

+

+    return true;

+}

+

+bool Texture::isMipmapFiltered() const

+{

+	switch(mMinFilter)

+    {

+    case GL_NEAREST:

+    case GL_LINEAR:

+        return false;

+    case GL_NEAREST_MIPMAP_NEAREST:

+    case GL_LINEAR_MIPMAP_NEAREST:

+    case GL_NEAREST_MIPMAP_LINEAR:

+    case GL_LINEAR_MIPMAP_LINEAR:

+        return true;

+    default: UNREACHABLE();

+    }

+

+	return false;

+}

+

+Texture2D::Texture2D(GLuint id) : Texture(id)

+{

+	for(int i = 0; i < MIPMAP_LEVELS; i++)

+	{

+		image[i] = 0;

+	}

+

+    mSurface = NULL;

+

+	mColorbufferProxy = NULL;

+	mProxyRefs = 0;

+}

+

+Texture2D::~Texture2D()

+{

+	resource->lock(sw::DESTRUCT);

+

+	for(int i = 0; i < MIPMAP_LEVELS; i++)

+	{

+		if(image[i])

+		{

+			image[i]->unbind();

+			image[i] = 0;

+		}

+	}

+

+	resource->unlock();

+

+    if(mSurface)

+    {

+        mSurface->setBoundTexture(NULL);

+        mSurface = NULL;

+    }

+

+	mColorbufferProxy = NULL;

+}

+

+// We need to maintain a count of references to renderbuffers acting as 

+// proxies for this texture, so that we do not attempt to use a pointer 

+// to a renderbuffer proxy which has been deleted.

+void Texture2D::addProxyRef(const Renderbuffer *proxy)

+{

+    mProxyRefs++;

+}

+

+void Texture2D::releaseProxy(const Renderbuffer *proxy)

+{

+    if(mProxyRefs > 0)

+	{

+        mProxyRefs--;

+	}

+

+    if(mProxyRefs == 0)

+	{

+		mColorbufferProxy = NULL;

+	}

+}

+

+GLenum Texture2D::getTarget() const

+{

+    return GL_TEXTURE_2D;

+}

+

+GLsizei Texture2D::getWidth(GLenum target, GLint level) const

+{

+	ASSERT(target == GL_TEXTURE_2D);

+    return image[level] ? image[level]->getWidth() : 0;

+}

+

+GLsizei Texture2D::getHeight(GLenum target, GLint level) const

+{

+	ASSERT(target == GL_TEXTURE_2D);

+    return image[level] ? image[level]->getHeight() : 0;

+}

+

+GLenum Texture2D::getFormat(GLenum target, GLint level) const

+{

+	ASSERT(target == GL_TEXTURE_2D);

+    return image[level] ? image[level]->getFormat() : 0;

+}

+

+GLenum Texture2D::getType(GLenum target, GLint level) const

+{

+	ASSERT(target == GL_TEXTURE_2D);

+    return image[level] ? image[level]->getType() : 0;

+}

+

+sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const

+{

+	ASSERT(target == GL_TEXTURE_2D);

+	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;

+}

+

+int Texture2D::getLevelCount() const

+{

+	ASSERT(isSamplerComplete());

+	int levels = 0;

+

+	while(levels < MIPMAP_LEVELS && image[levels])

+	{

+		levels++;

+	}

+

+	return levels;

+}

+

+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+	if(image[level])

+	{

+		image[level]->unbind();

+	}

+

+	image[level] = new Image(this, width, height, format, type);

+

+	if(!image[level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    Texture::setImage(format, type, unpackAlignment, pixels, image[level]);

+}

+

+void Texture2D::bindTexImage(egl::Surface *surface)

+{

+    GLenum format;

+

+    switch(surface->getInternalFormat())

+    {

+    case sw::FORMAT_A8R8G8B8:

+        format = GL_RGBA;

+        break;

+    case sw::FORMAT_X8R8G8B8:

+        format = GL_RGB;

+        break;

+    default:

+        UNIMPLEMENTED();

+        return;

+    }

+

+	for(int level = 0; level < MIPMAP_LEVELS; level++)

+	{

+		if(image[level])

+		{

+			image[level]->unbind();

+			image[level] = 0;

+		}

+	}

+

+	image[0] = surface->getRenderTarget();

+

+    mSurface = surface;

+    mSurface->setBoundTexture(this);

+}

+

+void Texture2D::releaseTexImage()

+{

+    for(int level = 0; level < MIPMAP_LEVELS; level++)

+	{

+		if(image[level])

+		{

+			image[level]->unbind();

+			image[level] = 0;

+		}

+	}

+}

+

+void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)

+{

+	if(image[level])

+	{

+		image[level]->unbind();

+	}

+

+	image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);

+

+	if(!image[level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    Texture::setCompressedImage(imageSize, pixels, image[level]);

+}

+

+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+	Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);

+}

+

+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)

+{

+    Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);

+}

+

+void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+    Image *renderTarget = source->getRenderTarget();

+

+    if(!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+	if(image[level])

+	{

+		image[level]->unbind();

+	}

+

+	image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);

+

+	if(!image[level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    if(width != 0 && height != 0)

+    {

+		sw::Rect sourceRect = {x, y, x + width, y + height};

+		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

+

+        copy(renderTarget, sourceRect, format, 0, 0, image[level]);

+    }

+

+	renderTarget->release();

+}

+

+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+	if(!image[level])

+	{

+		return error(GL_INVALID_OPERATION);

+	}

+

+    if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    Image *renderTarget = source->getRenderTarget();

+

+    if(!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+	sw::Rect sourceRect = {x, y, x + width, y + height};

+	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

+

+	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);

+

+	renderTarget->release();

+}

+

+// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.

+bool Texture2D::isSamplerComplete() const

+{

+	if(!image[0])

+	{

+		return false;

+	}

+

+    GLsizei width = image[0]->getWidth();

+    GLsizei height = image[0]->getHeight();

+

+    if(width <= 0 || height <= 0)

+    {

+        return false;

+    }

+

+    if(isMipmapFiltered())

+    {

+        if(!isMipmapComplete())

+        {

+            return false;

+        }

+    }

+

+    return true;

+}

+

+// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.

+bool Texture2D::isMipmapComplete() const

+{

+    GLsizei width = image[0]->getWidth();

+    GLsizei height = image[0]->getHeight();

+

+    int q = log2(std::max(width, height));

+

+    for(int level = 1; level <= q; level++)

+    {

+		if(!image[level])

+		{

+			return false;

+		}

+

+        if(image[level]->getFormat() != image[0]->getFormat())

+        {

+            return false;

+        }

+

+        if(image[level]->getType() != image[0]->getType())

+        {

+            return false;

+        }

+

+        if(image[level]->getWidth() != std::max(1, width >> level))

+        {

+            return false;

+        }

+

+        if(image[level]->getHeight() != std::max(1, height >> level))

+        {

+            return false;

+        }

+    }

+

+    return true;

+}

+

+bool Texture2D::isCompressed(GLenum target, GLint level) const

+{

+    return IsCompressed(getFormat(target, level));

+}

+

+bool Texture2D::isDepth(GLenum target, GLint level) const

+{

+    return IsDepthTexture(getFormat(target, level));

+}

+

+void Texture2D::generateMipmaps()

+{

+	if(!image[0])

+	{

+		return;   // FIXME: error?

+	}

+

+    unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));

+    

+	for(unsigned int i = 1; i <= q; i++)

+    {

+		if(image[i])

+		{

+			image[i]->unbind();

+		}

+

+		image[i] = new Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());

+

+		if(!image[i])

+		{

+			return error(GL_OUT_OF_MEMORY);

+		}

+

+		getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);

+    }

+}

+

+Image *Texture2D::getImage(unsigned int level)

+{

+	return image[level];

+}

+

+Renderbuffer *Texture2D::getRenderbuffer(GLenum target)

+{

+    if(target != GL_TEXTURE_2D)

+    {

+        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);

+    }

+

+    if(mColorbufferProxy == NULL)

+    {

+        mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this));

+    }

+

+    return mColorbufferProxy;

+}

+

+Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)

+{

+    ASSERT(target == GL_TEXTURE_2D);

+	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

+

+	if(image[level])

+	{

+		image[level]->addRef();

+	}

+

+	return image[level];

+}

+

+bool Texture2D::isShared(GLenum target, unsigned int level) const

+{

+    ASSERT(target == GL_TEXTURE_2D);

+    ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

+

+    if(mSurface)   // Bound to an EGLSurface

+    {

+        return true;

+    }

+

+    if(!image[level])

+    {

+        return false;

+    }

+

+    return image[level]->isShared();

+}

+

+TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)

+{

+	for(int f = 0; f < 6; f++)

+	{

+		for(int i = 0; i < MIPMAP_LEVELS; i++)

+		{

+			image[f][i] = 0;

+		}

+	}

+

+	for(int f = 0; f < 6; f++)

+    {

+        mFaceProxies[f] = NULL;

+        mFaceProxyRefs[f] = 0;

+	}

+}

+

+TextureCubeMap::~TextureCubeMap()

+{

+	resource->lock(sw::DESTRUCT);

+

+	for(int f = 0; f < 6; f++)

+	{

+		for(int i = 0; i < MIPMAP_LEVELS; i++)

+		{

+			if(image[f][i])

+			{

+				image[f][i]->unbind();

+				image[f][i] = 0;

+			}

+		}

+	}

+

+	resource->unlock();

+

+    for(int i = 0; i < 6; i++)

+    {

+        mFaceProxies[i] = NULL;

+    }

+}

+

+// We need to maintain a count of references to renderbuffers acting as 

+// proxies for this texture, so that the texture is not deleted while 

+// proxy references still exist. If the reference count drops to zero,

+// we set our proxy pointer NULL, so that a new attempt at referencing

+// will cause recreation.

+void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)

+{

+    for(int f = 0; f < 6; f++)

+    {

+        if(mFaceProxies[f] == proxy)

+        {

+			mFaceProxyRefs[f]++;

+		}

+	}

+}

+

+void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)

+{

+    for(int f = 0; f < 6; f++)

+    {

+        if(mFaceProxies[f] == proxy)

+        {

+            if(mFaceProxyRefs[f] > 0)

+			{

+				mFaceProxyRefs[f]--;

+			}

+

+            if(mFaceProxyRefs[f] == 0)

+			{

+				mFaceProxies[f] = NULL;

+			}

+		}

+    }

+}

+

+GLenum TextureCubeMap::getTarget() const

+{

+    return GL_TEXTURE_CUBE_MAP;

+}

+

+GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const

+{

+	int face = CubeFaceIndex(target);

+    return image[face][level] ? image[face][level]->getWidth() : 0;

+}

+

+GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const

+{

+	int face = CubeFaceIndex(target);

+    return image[face][level] ? image[face][level]->getHeight() : 0;

+}

+

+GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const

+{

+	int face = CubeFaceIndex(target);

+    return image[face][level] ? image[face][level]->getFormat() : 0;

+}

+

+GLenum TextureCubeMap::getType(GLenum target, GLint level) const

+{

+	int face = CubeFaceIndex(target);

+    return image[face][level] ? image[face][level]->getType() : 0;

+}

+

+sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const

+{

+	int face = CubeFaceIndex(target);

+    return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;

+}

+

+int TextureCubeMap::getLevelCount() const

+{

+	ASSERT(isSamplerComplete());

+	int levels = 0;

+

+	while(levels < MIPMAP_LEVELS && image[0][levels])

+	{

+		levels++;

+	}

+

+	return levels;

+}

+

+void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)

+{

+	int face = CubeFaceIndex(target);

+

+	if(image[face][level])

+	{

+		image[face][level]->unbind();

+	}

+

+	image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);

+

+	if(!image[face][level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    Texture::setCompressedImage(imageSize, pixels, image[face][level]);

+}

+

+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[CubeFaceIndex(target)][level]);

+}

+

+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)

+{

+    Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);

+}

+

+// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.

+bool TextureCubeMap::isSamplerComplete() const

+{

+	for(int face = 0; face < 6; face++)

+    {

+		if(!image[face][0])

+		{

+			return false;

+		}

+	}

+

+    int size = image[0][0]->getWidth();

+

+    if(size <= 0)

+    {

+        return false;

+    }

+

+    if(!isMipmapFiltered())

+    {

+        if(!isCubeComplete())

+        {

+            return false;

+        }

+    }

+    else

+    {

+        if(!isMipmapCubeComplete())   // Also tests for isCubeComplete()

+        {

+            return false;

+        }

+    }

+

+    return true;

+}

+

+// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.

+bool TextureCubeMap::isCubeComplete() const

+{

+    if(image[0][0]->getWidth() <= 0 || image[0][0]->getHeight() != image[0][0]->getWidth())

+    {

+        return false;

+    }

+

+    for(unsigned int face = 1; face < 6; face++)

+    {

+        if(image[face][0]->getWidth()  != image[0][0]->getWidth() ||

+           image[face][0]->getWidth()  != image[0][0]->getHeight() ||

+           image[face][0]->getFormat() != image[0][0]->getFormat() ||

+           image[face][0]->getType()   != image[0][0]->getType())

+        {

+            return false;

+        }

+    }

+

+    return true;

+}

+

+bool TextureCubeMap::isMipmapCubeComplete() const

+{

+    if(!isCubeComplete())

+    {

+        return false;

+    }

+

+    GLsizei size = image[0][0]->getWidth();

+    int q = log2(size);

+

+    for(int face = 0; face < 6; face++)

+    {

+        for(int level = 1; level <= q; level++)

+        {

+			if(!image[face][level])

+			{

+				return false;

+			}

+

+            if(image[face][level]->getFormat() != image[0][0]->getFormat())

+            {

+                return false;

+            }

+

+            if(image[face][level]->getType() != image[0][0]->getType())

+            {

+                return false;

+            }

+

+            if(image[face][level]->getWidth() != std::max(1, size >> level))

+            {

+                return false;

+            }

+        }

+    }

+

+    return true;

+}

+

+bool TextureCubeMap::isCompressed(GLenum target, GLint level) const

+{

+    return IsCompressed(getFormat(target, level));

+}

+

+bool TextureCubeMap::isDepth(GLenum target, GLint level) const

+{

+    return IsDepthTexture(getFormat(target, level));

+}

+

+void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+	int face = CubeFaceIndex(target);

+

+	if(image[face][level])

+	{

+		image[face][level]->unbind();

+	}

+

+	image[face][level] = new Image(this, width, height, format, type);

+

+	if(!image[face][level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    Texture::setImage(format, type, unpackAlignment, pixels, image[face][level]);

+}

+

+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+	Image *renderTarget = source->getRenderTarget();

+

+    if(!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+	int face = CubeFaceIndex(target);

+

+	if(image[face][level])

+	{

+		image[face][level]->unbind();

+	}

+

+	image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);

+

+	if(!image[face][level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+    if(width != 0 && height != 0)

+    {

+		sw::Rect sourceRect = {x, y, x + width, y + height};

+		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

+        

+        copy(renderTarget, sourceRect, format, 0, 0, image[face][level]);

+    }

+

+	renderTarget->release();

+}

+

+Image *TextureCubeMap::getImage(int face, unsigned int level)

+{

+	return image[face][level];

+}

+

+Image *TextureCubeMap::getImage(GLenum face, unsigned int level)

+{

+    return image[CubeFaceIndex(face)][level];

+}

+

+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+	int face = CubeFaceIndex(target);

+

+	if(!image[face][level])

+	{

+		return error(GL_INVALID_OPERATION);

+	}

+

+    GLsizei size = image[face][level]->getWidth();

+

+    if(xoffset + width > size || yoffset + height > size)

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    Image *renderTarget = source->getRenderTarget();

+

+    if(!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+	sw::Rect sourceRect = {x, y, x + width, y + height};

+	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

+

+	copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, image[face][level]);

+

+	renderTarget->release();

+}

+

+void TextureCubeMap::generateMipmaps()

+{

+    if(!isCubeComplete())

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    unsigned int q = log2(image[0][0]->getWidth());

+

+	for(unsigned int f = 0; f < 6; f++)

+    {

+		for(unsigned int i = 1; i <= q; i++)

+		{

+			if(image[f][i])

+			{

+				image[f][i]->unbind();

+			}

+

+			image[f][i] = new Image(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType());

+

+			if(!image[f][i])

+			{

+				return error(GL_OUT_OF_MEMORY);

+			}

+

+			getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);

+		}

+	}

+}

+

+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)

+{

+    if(!IsCubemapTextureTarget(target))

+    {

+        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);

+    }

+

+    int face = CubeFaceIndex(target);

+

+    if(mFaceProxies[face] == NULL)

+    {

+        mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));

+    }

+

+    return mFaceProxies[face];

+}

+

+Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)

+{

+    ASSERT(IsCubemapTextureTarget(target));

+    ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

+    

+	int face = CubeFaceIndex(target);

+

+	if(image[face][level])

+	{

+		image[face][level]->addRef();

+	}

+

+	return image[face][level];

+}

+

+bool TextureCubeMap::isShared(GLenum target, unsigned int level) const

+{

+    ASSERT(IsCubemapTextureTarget(target));

+    ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

+

+    int face = CubeFaceIndex(target);

+

+    if(!image[face][level])

+    {

+        return false;

+    }

+

+    return image[face][level]->isShared();

+}

+

+TextureExternal::TextureExternal(GLuint id) : Texture2D(id)

+{

+    mMinFilter = GL_LINEAR;

+    mMagFilter = GL_LINEAR;

+    mWrapS = GL_CLAMP_TO_EDGE;

+    mWrapT = GL_CLAMP_TO_EDGE;

+}

+

+TextureExternal::~TextureExternal()

+{

+}

+

+GLenum TextureExternal::getTarget() const

+{

+    return GL_TEXTURE_EXTERNAL_OES;

+}

+

+void TextureExternal::setImage(Image *sharedImage)

+{

+    if(image[0])

+    {

+        image[0]->release();

+    }

+

+    sharedImage->addRef();

+    image[0] = sharedImage;

+}

+

+}

+

+// Exported functions for use by EGL

+extern "C"

+{

+	gl::Image *createBackBuffer(int width, int height, const egl::Config *config)

+	{

+		if(config)

+		{

+			return new gl::Image(0, width, height, config->mAlphaSize ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);

+		}

+

+		return 0;

+	}

+}

diff --git a/src/GLES2/libGLES_CM/Texture.h b/src/GLES2/libGLES_CM/Texture.h
new file mode 100644
index 0000000..085fe92
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Texture.h
@@ -0,0 +1,238 @@
+// 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.

+//

+

+// Texture.h: Defines the abstract Texture class and its concrete derived

+// classes Texture2D and TextureCubeMap. Implements GL texture objects and

+// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.

+

+#ifndef LIBGLESV2_TEXTURE_H_

+#define LIBGLESV2_TEXTURE_H_

+

+#include "Renderbuffer.h"

+#include "RefCountObject.h"

+#include "utilities.h"

+#include "common/debug.h"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+#include <vector>

+

+namespace egl

+{

+class Surface;

+class Config;

+}

+

+namespace gl

+{

+class Framebuffer;

+

+enum

+{

+	IMPLEMENTATION_MAX_TEXTURE_LEVELS = MIPMAP_LEVELS,

+    IMPLEMENTATION_MAX_TEXTURE_SIZE = 1 << (MIPMAP_LEVELS - 1),

+    IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 1 << (MIPMAP_LEVELS - 1),

+	IMPLEMENTATION_MAX_RENDERBUFFER_SIZE = OUTLINE_RESOLUTION,

+	IMPLEMENTATION_MAX_SAMPLES = 4

+};

+

+class Texture : public RefCountObject

+{

+public:

+    explicit Texture(GLuint id);

+

+    virtual ~Texture();

+

+	sw::Resource *getResource() const;

+

+	virtual void addProxyRef(const Renderbuffer *proxy) = 0;

+    virtual void releaseProxy(const Renderbuffer *proxy) = 0;

+

+    virtual GLenum getTarget() const = 0;

+

+    bool setMinFilter(GLenum filter);

+    bool setMagFilter(GLenum filter);

+    bool setWrapS(GLenum wrap);

+    bool setWrapT(GLenum wrap);

+	bool setMaxAnisotropy(GLfloat textureMaxAnisotropy);

+

+    GLenum getMinFilter() const;

+    GLenum getMagFilter() const;

+    GLenum getWrapS() const;

+    GLenum getWrapT() const;

+	GLfloat getMaxAnisotropy() const;

+

+    virtual GLsizei getWidth(GLenum target, GLint level) const = 0;

+    virtual GLsizei getHeight(GLenum target, GLint level) const = 0;

+    virtual GLenum getFormat(GLenum target, GLint level) const = 0;

+    virtual GLenum getType(GLenum target, GLint level) const = 0;

+    virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;

+	virtual int getLevelCount() const = 0;

+

+    virtual bool isSamplerComplete() const = 0;

+    virtual bool isCompressed(GLenum target, GLint level) const = 0;

+	virtual bool isDepth(GLenum target, GLint level) const = 0;

+

+    virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;

+    virtual Image *getRenderTarget(GLenum target, unsigned int level) = 0;

+    virtual Image *createSharedImage(GLenum target, unsigned int level);

+    virtual bool isShared(GLenum target, unsigned int level) const = 0;

+

+    virtual void generateMipmaps() = 0;

+    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;

+

+protected:

+    void setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image);

+    void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image);

+    void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image);

+    void subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image);

+

+	bool copy(Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, Image *dest);

+

+	bool isMipmapFiltered() const;

+

+    GLenum mMinFilter;

+    GLenum mMagFilter;

+    GLenum mWrapS;

+    GLenum mWrapT;

+	GLfloat mMaxAnisotropy;

+

+	sw::Resource *resource;

+};

+

+class Texture2D : public Texture

+{

+public:

+    explicit Texture2D(GLuint id);

+

+    virtual ~Texture2D();

+

+	void addProxyRef(const Renderbuffer *proxy);

+    void releaseProxy(const Renderbuffer *proxy);

+

+    virtual GLenum getTarget() const;

+

+    virtual GLsizei getWidth(GLenum target, GLint level) const;

+    virtual GLsizei getHeight(GLenum target, GLint level) const;

+    virtual GLenum getFormat(GLenum target, GLint level) const;

+    virtual GLenum getType(GLenum target, GLint level) const;

+    virtual sw::Format getInternalFormat(GLenum target, GLint level) const;

+	virtual int getLevelCount() const;

+

+    void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);

+    void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);

+    void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);

+    void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);

+    void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

+    void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

+

+    virtual bool isSamplerComplete() const;

+    virtual bool isCompressed(GLenum target, GLint level) const;

+	virtual bool isDepth(GLenum target, GLint level) const;

+    virtual void bindTexImage(egl::Surface *surface);

+    virtual void releaseTexImage();

+

+    virtual void generateMipmaps();

+

+	virtual Renderbuffer *getRenderbuffer(GLenum target);

+    virtual Image *getRenderTarget(GLenum target, unsigned int level);

+	virtual bool isShared(GLenum target, unsigned int level) const;

+

+    Image *getImage(unsigned int level);

+

+protected:

+	bool isMipmapComplete() const;

+

+	Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS];

+    

+    egl::Surface *mSurface;

+    

+	// A specific internal reference count is kept for colorbuffer proxy references,

+    // because, as the renderbuffer acting as proxy will maintain a binding pointer

+    // back to this texture, there would be a circular reference if we used a binding

+    // pointer here. This reference count will cause the pointer to be set to NULL if

+    // the count drops to zero, but will not cause deletion of the Renderbuffer.

+    Renderbuffer *mColorbufferProxy;

+    unsigned int mProxyRefs;

+};

+

+class TextureCubeMap : public Texture

+{

+public:

+    explicit TextureCubeMap(GLuint id);

+

+    virtual ~TextureCubeMap();

+

+	void addProxyRef(const Renderbuffer *proxy);

+    void releaseProxy(const Renderbuffer *proxy);

+

+    virtual GLenum getTarget() const;

+    

+    virtual GLsizei getWidth(GLenum target, GLint level) const;

+    virtual GLsizei getHeight(GLenum target, GLint level) const;

+    virtual GLenum getFormat(GLenum target, GLint level) const;

+    virtual GLenum getType(GLenum target, GLint level) const;

+    virtual sw::Format getInternalFormat(GLenum target, GLint level) const;

+	virtual int getLevelCount() const;

+

+	void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);

+    void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);

+

+    void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);

+    void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);

+    void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

+    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

+

+    virtual bool isSamplerComplete() const;

+    virtual bool isCompressed(GLenum target, GLint level) const;

+	virtual bool isDepth(GLenum target, GLint level) const;

+

+    virtual void generateMipmaps();

+

+    virtual Renderbuffer *getRenderbuffer(GLenum target);

+	virtual Image *getRenderTarget(GLenum target, unsigned int level);

+	virtual bool isShared(GLenum target, unsigned int level) const;

+

+	Image *getImage(int face, unsigned int level);

+

+private:

+	bool isCubeComplete() const;

+	bool isMipmapCubeComplete() const;

+

+    // face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. Returns NULL on failure.

+    Image *getImage(GLenum face, unsigned int level);

+

+    Image *image[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];

+	

+	// A specific internal reference count is kept for colorbuffer proxy references,

+    // because, as the renderbuffer acting as proxy will maintain a binding pointer

+    // back to this texture, there would be a circular reference if we used a binding

+    // pointer here. This reference count will cause the pointer to be set to NULL if

+    // the count drops to zero, but will not cause deletion of the Renderbuffer.

+    Renderbuffer *mFaceProxies[6];

+	unsigned int mFaceProxyRefs[6];

+};

+

+class TextureExternal : public Texture2D

+{

+public:

+    explicit TextureExternal(GLuint id);

+

+    virtual ~TextureExternal();

+

+    virtual GLenum getTarget() const;

+

+    void setImage(Image *image);

+};

+}

+

+#endif   // LIBGLESV2_TEXTURE_H_

diff --git a/src/GLES2/libGLES_CM/VertexDataManager.cpp b/src/GLES2/libGLES_CM/VertexDataManager.cpp
new file mode 100644
index 0000000..ff88a6d
--- /dev/null
+++ b/src/GLES2/libGLES_CM/VertexDataManager.cpp
@@ -0,0 +1,334 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// VertexDataManager.h: Defines the VertexDataManager, a class that

+// runs the Buffer translation process.

+

+#include "VertexDataManager.h"

+

+#include "Buffer.h"

+#include "Program.h"

+#include "IndexDataManager.h"

+#include "common/debug.h"

+

+namespace

+{

+    enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024};

+}

+

+namespace gl

+{

+

+VertexDataManager::VertexDataManager(Context *context) : mContext(context)

+{

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+    {

+        mDirtyCurrentValue[i] = true;

+        mCurrentValueBuffer[i] = NULL;

+    }

+

+    mStreamingBuffer = new StreamingVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);

+

+    if(!mStreamingBuffer)

+    {

+        ERR("Failed to allocate the streaming vertex buffer.");

+    }

+}

+

+VertexDataManager::~VertexDataManager()

+{

+    delete mStreamingBuffer;

+

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+    {

+        delete mCurrentValueBuffer[i];

+    }

+}

+

+unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)

+{

+    Buffer *buffer = attribute.mBoundBuffer.get();

+

+    int inputStride = attribute.stride();

+    int elementSize = attribute.typeSize();

+    unsigned int streamOffset = 0;

+

+    char *output = NULL;

+    

+    if(vertexBuffer)

+    {

+        output = (char*)vertexBuffer->map(attribute, attribute.typeSize() * count, &streamOffset);

+    }

+

+    if(output == NULL)

+    {

+        ERR("Failed to map vertex buffer.");

+        return -1;

+    }

+

+    const char *input = NULL;

+

+    if(buffer)

+    {

+        int offset = attribute.mOffset;

+

+        input = static_cast<const char*>(buffer->data()) + offset;

+    }

+    else

+    {

+        input = static_cast<const char*>(attribute.mPointer);

+    }

+

+    input += inputStride * start;

+

+    if(inputStride == elementSize)

+    {

+        memcpy(output, input, count * inputStride);

+    }

+    else

+    {

+		for(int i = 0; i < count; i++)

+		{

+			memcpy(output, input, elementSize);

+			output += elementSize;

+			input += inputStride;

+		}

+    }

+

+    vertexBuffer->unmap();

+

+    return streamOffset;

+}

+

+GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)

+{

+    if(!mStreamingBuffer)

+    {

+        return GL_OUT_OF_MEMORY;

+    }

+

+    const VertexAttributeArray &attribs = mContext->getVertexAttributes();

+    Program *program = mContext->getCurrentProgram();

+

+    // Determine the required storage size per used buffer

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+    {

+        if(program->getAttributeStream(i) != -1 && attribs[i].mArrayEnabled)

+        {

+            if(!attribs[i].mBoundBuffer)

+            {

+                mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count);

+            }

+        }

+    }

+

+    mStreamingBuffer->reserveRequiredSpace();

+    

+    // Perform the vertex data translations

+    for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)

+    {

+        if(program->getAttributeStream(i) != -1)

+        {

+            if(attribs[i].mArrayEnabled)

+            {

+                Buffer *buffer = attribs[i].mBoundBuffer.get();

+

+                if(!buffer && attribs[i].mPointer == NULL)

+                {

+                    // This is an application error that would normally result in a crash, but we catch it and return an error

+                    ERR("An enabled vertex array has no buffer and no pointer.");

+                    return GL_INVALID_OPERATION;

+                }

+

+                sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;

+

+                if(staticBuffer)

+                {

+					translated[i].vertexBuffer = staticBuffer;

+					translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset;

+					translated[i].stride = attribs[i].stride();

+                }

+                else

+                {

+                    unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);

+

+					if(streamOffset == -1)

+					{

+						return GL_OUT_OF_MEMORY;

+					}

+

+					translated[i].vertexBuffer = mStreamingBuffer->getResource();

+					translated[i].offset = streamOffset;

+					translated[i].stride = attribs[i].typeSize();

+                }

+

+				switch(attribs[i].mType)

+				{

+				case GL_BYTE:           translated[i].type = sw::STREAMTYPE_SBYTE;  break;

+				case GL_UNSIGNED_BYTE:  translated[i].type = sw::STREAMTYPE_BYTE;   break;

+				case GL_SHORT:          translated[i].type = sw::STREAMTYPE_SHORT;  break;

+				case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break;

+				case GL_FIXED:          translated[i].type = sw::STREAMTYPE_FIXED;  break;

+				case GL_FLOAT:          translated[i].type = sw::STREAMTYPE_FLOAT;  break;

+				default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT;  break;

+				}

+

+				translated[i].count = attribs[i].mSize;

+				translated[i].normalized = attribs[i].mNormalized;

+            }

+            else

+            {

+                if(mDirtyCurrentValue[i])

+                {

+                    delete mCurrentValueBuffer[i];

+                    mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);

+                    mDirtyCurrentValue[i] = false;

+                }

+

+                translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource();

+

+                translated[i].type = sw::STREAMTYPE_FLOAT;

+				translated[i].count = 4;

+                translated[i].stride = 0;

+                translated[i].offset = 0;

+            }

+        }

+    }

+

+    return GL_NO_ERROR;

+}

+

+VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(NULL)

+{

+    if(size > 0)

+    {

+        mVertexBuffer = new sw::Resource(size + 1024);

+        

+        if(!mVertexBuffer)

+        {

+            ERR("Out of memory allocating a vertex buffer of size %lu.", size);

+        }

+    }

+}

+

+VertexBuffer::~VertexBuffer()

+{

+    if(mVertexBuffer)

+    {

+        mVertexBuffer->destruct();

+    }

+}

+

+void VertexBuffer::unmap()

+{

+    if(mVertexBuffer)

+    {

+		mVertexBuffer->unlock();

+    }

+}

+

+sw::Resource *VertexBuffer::getResource() const

+{

+    return mVertexBuffer;

+}

+

+ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float))

+{

+    if(mVertexBuffer)

+    {

+		float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC);

+     

+        vector[0] = x;

+        vector[1] = y;

+        vector[2] = z;

+        vector[3] = w;

+

+        mVertexBuffer->unlock();

+    }

+}

+

+ConstantVertexBuffer::~ConstantVertexBuffer()

+{

+}

+

+StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)

+{

+    mBufferSize = size;

+    mWritePosition = 0;

+    mRequiredSpace = 0;

+}

+

+StreamingVertexBuffer::~StreamingVertexBuffer()

+{

+}

+

+void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)

+{

+    mRequiredSpace += requiredSpace;

+}

+

+void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset)

+{

+    void *mapPtr = NULL;

+

+    if(mVertexBuffer)

+    {

+		mapPtr = (char*)mVertexBuffer->lock(sw::PUBLIC) + mWritePosition;

+        

+        if(!mapPtr)

+        {

+            ERR("Lock failed");

+            return NULL;

+        }

+

+        *offset = mWritePosition;

+        mWritePosition += requiredSpace;

+    }

+

+    return mapPtr;

+}

+

+void StreamingVertexBuffer::reserveRequiredSpace()

+{

+    if(mRequiredSpace > mBufferSize)

+    {

+        if(mVertexBuffer)

+        {

+            mVertexBuffer->destruct();

+            mVertexBuffer = 0;

+        }

+

+        mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2);   // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.

+

+		mVertexBuffer = new sw::Resource(mBufferSize);

+    

+        if(!mVertexBuffer)

+        {

+            ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);

+        }

+

+        mWritePosition = 0;

+    }

+    else if(mWritePosition + mRequiredSpace > mBufferSize)   // Recycle

+    {

+        if(mVertexBuffer)

+        {

+            mVertexBuffer->destruct();

+			mVertexBuffer = new sw::Resource(mBufferSize);

+        }

+

+        mWritePosition = 0;

+    }

+

+    mRequiredSpace = 0;

+}

+

+}

diff --git a/src/GLES2/libGLES_CM/VertexDataManager.h b/src/GLES2/libGLES_CM/VertexDataManager.h
new file mode 100644
index 0000000..8800219
--- /dev/null
+++ b/src/GLES2/libGLES_CM/VertexDataManager.h
@@ -0,0 +1,99 @@
+// SwiftShader Software Renderer

+//

+// Copyright(c) 2005-2012 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.

+//

+

+// VertexDataManager.h: Defines the VertexDataManager, a class that

+// runs the Buffer translation process.

+

+#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_

+#define LIBGLESV2_VERTEXDATAMANAGER_H_

+

+#include "Context.h"

+#include "Device.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+

+namespace gl

+{

+

+struct TranslatedAttribute

+{

+    sw::StreamType type;

+	int count;

+	bool normalized;

+

+    unsigned int offset;

+    unsigned int stride;   // 0 means not to advance the read pointer at all

+

+    sw::Resource *vertexBuffer;

+};

+

+class VertexBuffer

+{

+  public:

+    VertexBuffer(unsigned int size);

+    virtual ~VertexBuffer();

+

+    void unmap();

+

+    sw::Resource *getResource() const;

+

+  protected:

+    sw::Resource *mVertexBuffer;

+};

+

+class ConstantVertexBuffer : public VertexBuffer

+{

+  public:

+    ConstantVertexBuffer(float x, float y, float z, float w);

+    ~ConstantVertexBuffer();

+};

+

+class StreamingVertexBuffer : public VertexBuffer

+{

+  public:

+    StreamingVertexBuffer(unsigned int size);

+    ~StreamingVertexBuffer();

+

+    void *map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *streamOffset);

+    void reserveRequiredSpace();

+    void addRequiredSpace(unsigned int requiredSpace);

+

+  protected:

+    unsigned int mBufferSize;

+    unsigned int mWritePosition;

+    unsigned int mRequiredSpace;

+};

+

+class VertexDataManager

+{

+  public:

+    VertexDataManager(Context *context);

+    virtual ~VertexDataManager();

+

+    void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }

+

+    GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);

+

+  private:

+    unsigned int writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);

+

+    Context *const mContext;

+

+    StreamingVertexBuffer *mStreamingBuffer;

+

+    bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];

+    ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];

+};

+

+}

+

+#endif   // LIBGLESV2_VERTEXDATAMANAGER_H_

diff --git a/src/GLES2/libGLES_CM/exports.map b/src/GLES2/libGLES_CM/exports.map
new file mode 100644
index 0000000..7d08ed0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/exports.map
@@ -0,0 +1,186 @@
+{
+global:
+    glActiveTexture;
+    glAttachShader;
+    glBindAttribLocation;
+    glBindBuffer;
+    glBindFramebuffer;
+    glBindRenderbuffer;
+    glBindTexture;
+    glBlendColor;
+    glBlendEquation;
+    glBlendEquationSeparate;
+    glBlendFunc;
+    glBlendFuncSeparate;
+    glBufferData;
+    glBufferSubData;
+    glCheckFramebufferStatus;
+    glClear;
+    glClearColor;
+    glClearDepthf;
+    glClearStencil;
+    glColorMask;
+    glCompileShader;
+    glCompressedTexImage2D;
+    glCompressedTexSubImage2D;
+    glCopyTexImage2D;
+    glCopyTexSubImage2D;
+    glCreateProgram;
+    glCreateShader;
+    glCullFace;
+    glDeleteBuffers;
+    glDeleteFramebuffers;
+    glDeleteProgram;
+    glDeleteRenderbuffers;
+    glDeleteShader;
+    glDeleteTextures;
+    glDepthFunc;
+    glDepthMask;
+    glDepthRangef;
+    glDetachShader;
+    glDisable;
+    glDisableVertexAttribArray;
+    glDrawArrays;
+    glDrawElements;
+    glEnable;
+    glEnableVertexAttribArray;
+    glFinish;
+    glFlush;
+    glFramebufferRenderbuffer;
+    glFramebufferTexture2D;
+    glFrontFace;
+    glGenBuffers;
+    glGenFramebuffers;
+    glGenRenderbuffers;
+    glGenTextures;
+    glGenerateMipmap;
+    glGetActiveAttrib;
+    glGetActiveUniform;
+    glGetAttachedShaders;
+    glGetAttribLocation;
+    glGetBooleanv;
+    glGetBufferParameteriv;
+    glGetError;
+    glGetFloatv;
+    glGetFramebufferAttachmentParameteriv;
+    glGetIntegerv;
+    glGetProgramInfoLog;
+    glGetProgramiv;
+    glGetRenderbufferParameteriv;
+    glGetShaderInfoLog;
+    glGetShaderPrecisionFormat;
+    glGetShaderSource;
+    glGetShaderiv;
+    glGetString;
+    glGetTexParameterfv;
+    glGetTexParameteriv;
+    glGetUniformLocation;
+    glGetUniformfv;
+    glGetUniformiv;
+    glGetVertexAttribPointerv;
+    glGetVertexAttribfv;
+    glGetVertexAttribiv;
+    glHint;
+    glIsBuffer;
+    glIsEnabled;
+    glIsFramebuffer;
+    glIsProgram;
+    glIsRenderbuffer;
+    glIsShader;
+    glIsTexture;
+    glLineWidth;
+    glLinkProgram;
+    glPixelStorei;
+    glPolygonOffset;
+    glReadPixels;
+    glReleaseShaderCompiler;
+    glRenderbufferStorage;
+    glSampleCoverage;
+    glScissor;
+    glShaderBinary;
+    glShaderSource;
+    glStencilFunc;
+    glStencilFuncSeparate;
+    glStencilMask;
+    glStencilMaskSeparate;
+    glStencilOp;
+    glStencilOpSeparate;
+    glTexImage2D;
+    glTexParameterf;
+    glTexParameterfv;
+    glTexParameteri;
+    glTexParameteriv;
+    glTexSubImage2D;
+    glUniform1f;
+    glUniform1fv;
+    glUniform1i;
+    glUniform1iv;
+    glUniform2f;
+    glUniform2fv;
+    glUniform2i;
+    glUniform2iv;
+    glUniform3f;
+    glUniform3fv;
+    glUniform3i;
+    glUniform3iv;
+    glUniform4f;
+    glUniform4fv;
+    glUniform4i;
+    glUniform4iv;
+    glUniformMatrix2fv;
+    glUniformMatrix3fv;
+    glUniformMatrix4fv;
+    glUseProgram;
+    glValidateProgram;
+    glVertexAttrib1f;
+    glVertexAttrib1fv;
+    glVertexAttrib2f;
+    glVertexAttrib2fv;
+    glVertexAttrib3f;
+    glVertexAttrib3fv;
+    glVertexAttrib4f;
+    glVertexAttrib4fv;
+    glVertexAttribPointer;
+    glViewport;
+
+    # Extensions
+    glTexImage3DOES;
+    glBlitFramebufferANGLE;
+    glRenderbufferStorageMultisampleANGLE;
+    glDeleteFencesNV;
+    glFinishFenceNV;
+    glGenFencesNV;
+    glGetFenceivNV;
+    glIsFenceNV;
+    glSetFenceNV;
+    glTestFenceNV;
+    glGetGraphicsResetStatusEXT;
+    glReadnPixelsEXT;
+    glGetnUniformfvEXT;
+    glGetnUniformivEXT;
+    glGenQueriesEXT;
+    glDeleteQueriesEXT;
+    glIsQueryEXT;
+    glBeginQueryEXT;
+    glEndQueryEXT;
+    glGetQueryivEXT;
+    glGetQueryObjectuivEXT;
+
+    # EGL dependencies
+    glCreateContext;
+    glDestroyContext;
+    glMakeCurrent;
+    glGetCurrentContext;
+    glGetProcAddress;
+    glBindTexImage;
+
+    createFrameBuffer;
+    createBackBuffer;
+    createDevice;
+
+    Register;
+
+local:
+    *;
+};
+
diff --git a/src/GLES2/libGLES_CM/libGLESv2.cbp b/src/GLES2/libGLES_CM/libGLESv2.cbp
new file mode 100644
index 0000000..a045a3a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.cbp
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="libGLESv2" />
+		<Option pch_mode="2" />
+		<Option compiler="gcc" />
+		<Build>
+			<Target title="Debug x86">
+				<Option output="./../../bin/x86/Debug/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+				<Option object_output="obj/x86/Debug/" />
+				<Option type="3" />
+				<Option compiler="gcc" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="-g" />
+					<Add option="-m32" />
+				</Compiler>
+				<Linker>
+					<Add option="-m32" />
+					<Add library="./../../LLVM/bin/x86/Debug/libLLVM.a" />
+				</Linker>
+			</Target>
+			<Target title="Release x86">
+				<Option output="./../../bin/x86/Release/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+				<Option object_output="obj/x86/Release/" />
+				<Option type="3" />
+				<Option compiler="gcc" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="-march=i686" />
+					<Add option="-fomit-frame-pointer" />
+					<Add option="-O2" />
+					<Add option="-m32" />
+					<Add option="-ffunction-sections" />
+					<Add option="-fdata-sections" />
+					<Add option="-DNDEBUG" />
+					<Add option="-DANGLE_DISABLE_TRACE" />
+				</Compiler>
+				<Linker>
+					<Add option="-s" />
+					<Add option="-m32" />
+					<Add option="-Wl,--gc-sections" />
+					<Add library="./../../LLVM/bin/x86/Release/libLLVM.a" />
+				</Linker>
+			</Target>
+			<Target title="Debug x64">
+				<Option output="./../../bin/x64/Debug/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+				<Option object_output="obj/x64/Debug/" />
+				<Option type="3" />
+				<Option compiler="gcc" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="-g" />
+					<Add option="-m64" />
+					<Add option="-fPIC" />
+				</Compiler>
+				<Linker>
+					<Add option="-m64" />
+					<Add library="./../../LLVM/bin/x64/Debug/libLLVM.a" />
+				</Linker>
+			</Target>
+			<Target title="Release x64">
+				<Option output="./../../bin/x64/Release/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+				<Option object_output="obj/x64/Release/" />
+				<Option type="3" />
+				<Option compiler="gcc" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="-march=core2" />
+					<Add option="-fomit-frame-pointer" />
+					<Add option="-O2" />
+					<Add option="-m64" />
+					<Add option="-fPIC" />
+					<Add option="-ffunction-sections" />
+					<Add option="-fdata-sections" />
+					<Add option="-DNDEBUG" />
+					<Add option="-DANGLE_DISABLE_TRACE" />
+				</Compiler>
+				<Linker>
+					<Add option="-s" />
+					<Add option="-m64" />
+					<Add option="-Wl,--gc-sections" />
+					<Add library="./../../LLVM/bin/x64/Release/libLLVM.a" />
+				</Linker>
+			</Target>
+		</Build>
+		<Compiler>
+			<Add option="-Wall" />
+			<Add option="-fexceptions" />
+			<Add option="-fno-operator-names" />
+			<Add option="-ffriend-injection" />
+			<Add option="-msse2" />
+			<Add option="-D__STDC_LIMIT_MACROS" />
+			<Add option="-D__STDC_CONSTANT_MACROS" />
+			<Add directory="./../" />
+			<Add directory="./../include/" />
+			<Add directory="./../../" />
+			<Add directory="./../../LLVM/include-linux/" />
+			<Add directory="./../../LLVM/include/" />
+			<Add directory="./../../LLVM/lib/Target/X86" />
+			<Add directory="./../../Renderer/" />
+			<Add directory="./../../Common/" />
+			<Add directory="./../../Shader/" />
+			<Add directory="./../../Main/" />
+		</Compiler>
+		<Linker>
+			<Add option="-Wl,--version-script=./exports.map" />
+			<Add library="pthread" />
+			<Add library="X11" />
+			<Add library="Xext" />
+		</Linker>
+		<Unit filename="./../../Common/CPUID.cpp" />
+		<Unit filename="./../../Common/CPUID.hpp" />
+		<Unit filename="./../../Common/Configurator.cpp" />
+		<Unit filename="./../../Common/Configurator.hpp" />
+		<Unit filename="./../../Common/Debug.cpp" />
+		<Unit filename="./../../Common/Debug.hpp" />
+		<Unit filename="./../../Common/ExceptionHandling.hpp" />
+		<Unit filename="./../../Common/Half.cpp" />
+		<Unit filename="./../../Common/Half.hpp" />
+		<Unit filename="./../../Common/Math.cpp" />
+		<Unit filename="./../../Common/Math.hpp" />
+		<Unit filename="./../../Common/Memory.cpp" />
+		<Unit filename="./../../Common/Memory.hpp" />
+		<Unit filename="./../../Common/MetaMacro.hpp" />
+		<Unit filename="./../../Common/MutexLock.hpp" />
+		<Unit filename="./../../Common/Resource.cpp" />
+		<Unit filename="./../../Common/Resource.hpp" />
+		<Unit filename="./../../Common/Socket.cpp" />
+		<Unit filename="./../../Common/Socket.hpp" />
+		<Unit filename="./../../Common/Thread.cpp" />
+		<Unit filename="./../../Common/Thread.hpp" />
+		<Unit filename="./../../Common/Timer.cpp" />
+		<Unit filename="./../../Common/Timer.hpp" />
+		<Unit filename="./../../Common/Types.hpp" />
+		<Unit filename="./../../Common/Version.h" />
+		<Unit filename="./../common/debug.cpp" />
+		<Unit filename="./../common/debug.h" />
+		<Unit filename="../compiler/AnalyzeCallDepth.cpp" />
+		<Unit filename="../compiler/AnalyzeCallDepth.h" />
+		<Unit filename="../compiler/BaseTypes.h" />
+		<Unit filename="../compiler/Common.h" />
+		<Unit filename="../compiler/Compiler.cpp" />
+		<Unit filename="../compiler/ConstantUnion.h" />
+		<Unit filename="../compiler/Diagnostics.cpp" />
+		<Unit filename="../compiler/Diagnostics.h" />
+		<Unit filename="../compiler/DirectiveHandler.cpp" />
+		<Unit filename="../compiler/DirectiveHandler.h" />
+		<Unit filename="../compiler/ExtensionBehavior.h" />
+		<Unit filename="../compiler/InfoSink.cpp" />
+		<Unit filename="../compiler/InfoSink.h" />
+		<Unit filename="../compiler/Initialize.cpp" />
+		<Unit filename="../compiler/Initialize.h" />
+		<Unit filename="../compiler/InitializeDll.cpp" />
+		<Unit filename="../compiler/InitializeDll.h" />
+		<Unit filename="../compiler/InitializeGlobals.h" />
+		<Unit filename="../compiler/InitializeParseContext.cpp" />
+		<Unit filename="../compiler/InitializeParseContext.h" />
+		<Unit filename="../compiler/IntermTraverse.cpp" />
+		<Unit filename="../compiler/Intermediate.cpp" />
+		<Unit filename="../compiler/MMap.h" />
+		<Unit filename="../compiler/OutputASM.cpp" />
+		<Unit filename="../compiler/OutputASM.h" />
+		<Unit filename="../compiler/ParseHelper.cpp" />
+		<Unit filename="../compiler/ParseHelper.h" />
+		<Unit filename="../compiler/PoolAlloc.cpp" />
+		<Unit filename="../compiler/PoolAlloc.h" />
+		<Unit filename="../compiler/Pragma.h" />
+		<Unit filename="../compiler/RemoveTree.cpp" />
+		<Unit filename="../compiler/RemoveTree.h" />
+		<Unit filename="../compiler/ShHandle.h" />
+		<Unit filename="../compiler/ShaderLang.cpp" />
+		<Unit filename="../compiler/SymbolTable.cpp" />
+		<Unit filename="../compiler/SymbolTable.h" />
+		<Unit filename="../compiler/TranslatorASM.cpp" />
+		<Unit filename="../compiler/TranslatorASM.h" />
+		<Unit filename="../compiler/Types.h" />
+		<Unit filename="../compiler/ValidateLimitations.cpp" />
+		<Unit filename="../compiler/ValidateLimitations.h" />
+		<Unit filename="../compiler/debug.cpp" />
+		<Unit filename="../compiler/debug.h" />
+		<Unit filename="../compiler/glslang.h" />
+		<Unit filename="../compiler/glslang_lex.cpp" />
+		<Unit filename="../compiler/glslang_tab.cpp" />
+		<Unit filename="../compiler/glslang_tab.h" />
+		<Unit filename="../compiler/intermOut.cpp" />
+		<Unit filename="../compiler/intermediate.h" />
+		<Unit filename="../compiler/localintermediate.h" />
+		<Unit filename="../compiler/osinclude.h" />
+		<Unit filename="../compiler/ossource_posix.cpp" />
+		<Unit filename="../compiler/parseConst.cpp" />
+		<Unit filename="../compiler/preprocessor/Diagnostics.cpp" />
+		<Unit filename="../compiler/preprocessor/Diagnostics.h" />
+		<Unit filename="../compiler/preprocessor/DirectiveHandler.cpp" />
+		<Unit filename="../compiler/preprocessor/DirectiveHandler.h" />
+		<Unit filename="../compiler/preprocessor/DirectiveParser.cpp" />
+		<Unit filename="../compiler/preprocessor/DirectiveParser.h" />
+		<Unit filename="../compiler/preprocessor/ExpressionParser.cpp" />
+		<Unit filename="../compiler/preprocessor/ExpressionParser.h" />
+		<Unit filename="../compiler/preprocessor/Input.cpp" />
+		<Unit filename="../compiler/preprocessor/Input.h" />
+		<Unit filename="../compiler/preprocessor/Lexer.cpp" />
+		<Unit filename="../compiler/preprocessor/Lexer.h" />
+		<Unit filename="../compiler/preprocessor/Macro.cpp" />
+		<Unit filename="../compiler/preprocessor/Macro.h" />
+		<Unit filename="../compiler/preprocessor/MacroExpander.cpp" />
+		<Unit filename="../compiler/preprocessor/MacroExpander.h" />
+		<Unit filename="../compiler/preprocessor/Preprocessor.cpp" />
+		<Unit filename="../compiler/preprocessor/Preprocessor.h" />
+		<Unit filename="../compiler/preprocessor/SourceLocation.h" />
+		<Unit filename="../compiler/preprocessor/Token.cpp" />
+		<Unit filename="../compiler/preprocessor/Token.h" />
+		<Unit filename="../compiler/preprocessor/Tokenizer.cpp" />
+		<Unit filename="../compiler/preprocessor/Tokenizer.h" />
+		<Unit filename="../compiler/preprocessor/length_limits.h" />
+		<Unit filename="../compiler/preprocessor/numeric_lex.h" />
+		<Unit filename="../compiler/preprocessor/pp_utils.h" />
+		<Unit filename="../compiler/util.cpp" />
+		<Unit filename="../compiler/util.h" />
+		<Unit filename="./../include/EGL/egl.h" />
+		<Unit filename="./../include/EGL/eglext.h" />
+		<Unit filename="./../include/EGL/eglplatform.h" />
+		<Unit filename="./../include/GLES2/gl2.h" />
+		<Unit filename="./../include/GLES2/gl2ext.h" />
+		<Unit filename="./../include/GLES2/gl2platform.h" />
+		<Unit filename="./../include/GLSLANG/ShaderLang.h" />
+		<Unit filename="./../include/KHR/khrplatform.h" />
+		<Unit filename="./../libGLESv2/Buffer.cpp" />
+		<Unit filename="./../libGLESv2/Buffer.h" />
+		<Unit filename="./../libGLESv2/Context.cpp" />
+		<Unit filename="./../libGLESv2/Context.h" />
+		<Unit filename="./../libGLESv2/Device.cpp" />
+		<Unit filename="./../libGLESv2/Device.hpp" />
+		<Unit filename="./../libGLESv2/Fence.cpp" />
+		<Unit filename="./../libGLESv2/Fence.h" />
+		<Unit filename="./../libGLESv2/Framebuffer.cpp" />
+		<Unit filename="./../libGLESv2/Framebuffer.h" />
+		<Unit filename="./../libGLESv2/HandleAllocator.cpp" />
+		<Unit filename="./../libGLESv2/HandleAllocator.h" />
+		<Unit filename="./../libGLESv2/Image.cpp" />
+		<Unit filename="./../libGLESv2/Image.hpp" />
+		<Unit filename="./../libGLESv2/IndexDataManager.cpp" />
+		<Unit filename="./../libGLESv2/IndexDataManager.h" />
+		<Unit filename="./../libGLESv2/Program.cpp" />
+		<Unit filename="./../libGLESv2/Program.h" />
+		<Unit filename="./../libGLESv2/Query.cpp" />
+		<Unit filename="./../libGLESv2/Query.h" />
+		<Unit filename="./../libGLESv2/RefCountObject.cpp" />
+		<Unit filename="./../libGLESv2/RefCountObject.h" />
+		<Unit filename="./../libGLESv2/Renderbuffer.cpp" />
+		<Unit filename="./../libGLESv2/Renderbuffer.h" />
+		<Unit filename="./../libGLESv2/ResourceManager.cpp" />
+		<Unit filename="./../libGLESv2/ResourceManager.h" />
+		<Unit filename="./../libGLESv2/Shader.cpp" />
+		<Unit filename="./../libGLESv2/Shader.h" />
+		<Unit filename="./../libGLESv2/Texture.cpp" />
+		<Unit filename="./../libGLESv2/Texture.h" />
+		<Unit filename="./../libGLESv2/Unknown.hpp" />
+		<Unit filename="./../libGLESv2/VertexDataManager.cpp" />
+		<Unit filename="./../libGLESv2/VertexDataManager.h" />
+		<Unit filename="./../libGLESv2/libGLESv2.cpp" />
+		<Unit filename="./../libGLESv2/main.cpp" />
+		<Unit filename="./../libGLESv2/main.h" />
+		<Unit filename="./../libGLESv2/mathutil.h" />
+		<Unit filename="./../libGLESv2/resource.h" />
+		<Unit filename="./../libGLESv2/utilities.cpp" />
+		<Unit filename="./../libGLESv2/utilities.h" />
+		<Unit filename="./../libGLESv2/vertexconversion.h" />
+		<Unit filename="./../../Main/Config.cpp" />
+		<Unit filename="./../../Main/Config.hpp" />
+		<Unit filename="./../../Main/FrameBuffer.cpp" />
+		<Unit filename="./../../Main/FrameBuffer.hpp" />
+		<Unit filename="./../../Main/FrameBufferX11.cpp" />
+		<Unit filename="./../../Main/FrameBufferX11.hpp" />
+		<Unit filename="./../../Main/Logo.cpp" />
+		<Unit filename="./../../Main/Register.cpp" />
+		<Unit filename="./../../Main/Register.hpp" />
+		<Unit filename="./../../Main/SwiftConfig.cpp" />
+		<Unit filename="./../../Main/SwiftConfig.hpp" />
+		<Unit filename="./../../Main/crc.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="./../../Main/crc.h" />
+		<Unit filename="./../../Main/serialcommon.h" />
+		<Unit filename="./../../Main/serialvalid.cpp" />
+		<Unit filename="./../../Main/serialvalid.h" />
+		<Unit filename="./../../Reactor/Routine.cpp" />
+		<Unit filename="./../../Reactor/Routine.hpp" />
+		<Unit filename="./../../Reactor/RoutineManager.cpp" />
+		<Unit filename="./../../Reactor/RoutineManager.hpp" />
+		<Unit filename="./../../Reactor/Nucleus.cpp" />
+		<Unit filename="./../../Reactor/Nucleus.hpp" />
+		<Unit filename="./../../Reactor/Reactor.hpp" />
+		<Unit filename="./../../Reactor/x86.hpp" />
+		<Unit filename="./../../Renderer/Blitter.cpp" />
+		<Unit filename="./../../Renderer/Blitter.hpp" />
+		<Unit filename="./../../Renderer/Clipper.cpp" />
+		<Unit filename="./../../Renderer/Clipper.hpp" />
+		<Unit filename="./../../Renderer/Color.cpp" />
+		<Unit filename="./../../Renderer/Color.hpp" />
+		<Unit filename="./../../Renderer/Context.cpp" />
+		<Unit filename="./../../Renderer/Context.hpp" />
+		<Unit filename="./../../Renderer/LRUCache.hpp" />
+		<Unit filename="./../../Renderer/Matrix.cpp" />
+		<Unit filename="./../../Renderer/Matrix.hpp" />
+		<Unit filename="./../../Renderer/PixelProcessor.cpp" />
+		<Unit filename="./../../Renderer/PixelProcessor.hpp" />
+		<Unit filename="./../../Renderer/Plane.cpp" />
+		<Unit filename="./../../Renderer/Plane.hpp" />
+		<Unit filename="./../../Renderer/Point.cpp" />
+		<Unit filename="./../../Renderer/Point.hpp" />
+		<Unit filename="./../../Renderer/Polygon.hpp" />
+		<Unit filename="./../../Renderer/Primitive.hpp" />
+		<Unit filename="./../../Renderer/QuadRasterizer.cpp" />
+		<Unit filename="./../../Renderer/QuadRasterizer.hpp" />
+		<Unit filename="./../../Renderer/Rasterizer.cpp" />
+		<Unit filename="./../../Renderer/Rasterizer.hpp" />
+		<Unit filename="./../../Renderer/Renderer.cpp" />
+		<Unit filename="./../../Renderer/Renderer.hpp" />
+		<Unit filename="./../../Renderer/Sampler.cpp" />
+		<Unit filename="./../../Renderer/Sampler.hpp" />
+		<Unit filename="./../../Renderer/SetupProcessor.cpp" />
+		<Unit filename="./../../Renderer/SetupProcessor.hpp" />
+		<Unit filename="./../../Renderer/Stream.hpp" />
+		<Unit filename="./../../Renderer/Surface.cpp" />
+		<Unit filename="./../../Renderer/Surface.hpp" />
+		<Unit filename="./../../Renderer/TextureStage.cpp" />
+		<Unit filename="./../../Renderer/TextureStage.hpp" />
+		<Unit filename="./../../Renderer/Triangle.hpp" />
+		<Unit filename="./../../Renderer/Vector.cpp" />
+		<Unit filename="./../../Renderer/Vector.hpp" />
+		<Unit filename="./../../Renderer/Vertex.hpp" />
+		<Unit filename="./../../Renderer/VertexProcessor.cpp" />
+		<Unit filename="./../../Renderer/VertexProcessor.hpp" />
+		<Unit filename="./../../Shader/Constants.cpp" />
+		<Unit filename="./../../Shader/Constants.hpp" />
+		<Unit filename="./../../Shader/PixelRoutine.cpp" />
+		<Unit filename="./../../Shader/PixelRoutine.hpp" />
+		<Unit filename="./../../Shader/PixelShader.cpp" />
+		<Unit filename="./../../Shader/PixelShader.hpp" />
+		<Unit filename="./../../Shader/SamplerCore.cpp" />
+		<Unit filename="./../../Shader/SamplerCore.hpp" />
+		<Unit filename="./../../Shader/SetupRoutine.cpp" />
+		<Unit filename="./../../Shader/SetupRoutine.hpp" />
+		<Unit filename="./../../Shader/Shader.cpp" />
+		<Unit filename="./../../Shader/Shader.hpp" />
+		<Unit filename="./../../Shader/ShaderCore.cpp" />
+		<Unit filename="./../../Shader/ShaderCore.hpp" />
+		<Unit filename="./../../Shader/VertexPipeline.cpp" />
+		<Unit filename="./../../Shader/VertexPipeline.hpp" />
+		<Unit filename="./../../Shader/VertexProgram.cpp" />
+		<Unit filename="./../../Shader/VertexProgram.hpp" />
+		<Unit filename="./../../Shader/VertexRoutine.cpp" />
+		<Unit filename="./../../Shader/VertexRoutine.hpp" />
+		<Unit filename="./../../Shader/VertexShader.cpp" />
+		<Unit filename="./../../Shader/VertexShader.hpp" />
+		<Extensions>
+			<code_completion />
+			<debugger />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>
diff --git a/src/GLES2/libGLES_CM/libGLESv2.cpp b/src/GLES2/libGLES_CM/libGLESv2.cpp
new file mode 100644
index 0000000..cde61ed
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.cpp
@@ -0,0 +1,6214 @@
+// 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.

+//

+// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.

+

+#include "main.h"

+#include "mathutil.h"

+#include "utilities.h"

+#include "Buffer.h"

+#include "Context.h"

+#include "Fence.h"

+#include "Framebuffer.h"

+#include "Program.h"

+#include "Renderbuffer.h"

+#include "Shader.h"

+#include "Texture.h"

+#include "Query.h"

+#include "common/debug.h"

+#include "Common/Version.h"

+#include "Main/Register.hpp"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+#include <GLES2/gl2ext.h>

+

+#include <exception>

+#include <limits>

+

+static bool validImageSize(GLint level, GLsizei width, GLsizei height)

+{

+    if(level < 0 || level >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)

+    {

+        return false;

+    }

+

+    return true;

+}

+

+static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, gl::Texture *texture)

+{

+    if(!texture)

+    {

+        return error(GL_INVALID_OPERATION, false);

+    }

+

+    if(compressed != texture->isCompressed(target, level))

+    {

+        return error(GL_INVALID_OPERATION, false);

+    }

+

+    if(format != GL_NONE && format != texture->getFormat(target, level))

+    {

+        return error(GL_INVALID_OPERATION, false);

+    }

+

+    if(compressed)

+    {

+        if((width % 4 != 0 && width != texture->getWidth(target, 0)) || 

+           (height % 4 != 0 && height != texture->getHeight(target, 0)))

+        {

+            return error(GL_INVALID_OPERATION, false);

+        }

+    }

+

+    if(xoffset + width > texture->getWidth(target, level) ||

+       yoffset + height > texture->getHeight(target, level))

+    {

+        return error(GL_INVALID_VALUE, false);

+    }

+

+    return true;

+}

+

+// Check for combinations of format and type that are valid for ReadPixels

+static bool validReadFormatType(GLenum format, GLenum type)

+{

+    switch(format)

+    {

+    case GL_RGBA:

+        switch (type)

+        {

+        case GL_UNSIGNED_BYTE:

+            break;

+        default:

+            return false;

+        }

+        break;

+    case GL_BGRA_EXT:

+        switch (type)

+        {

+        case GL_UNSIGNED_BYTE:

+        case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:

+        case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:

+            break;

+        default:

+            return false;

+        }

+        break;

+    case gl::IMPLEMENTATION_COLOR_READ_FORMAT:

+        switch (type)

+        {

+        case gl::IMPLEMENTATION_COLOR_READ_TYPE:

+            break;

+        default:

+            return false;

+        }

+        break;

+    default:

+        return false;

+    }

+

+    return true;

+}

+

+extern "C"

+{

+

+void GL_APIENTRY glActiveTexture(GLenum texture)

+{

+    TRACE("(GLenum texture = 0x%X)", texture);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+

+            context->setActiveSampler(texture - GL_TEXTURE0);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glAttachShader(GLuint program, GLuint shader)

+{

+    TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(!shaderObject)

+            {

+                if(context->getProgram(shader))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(!programObject->attachShader(shaderObject))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint id)

+{

+    TRACE("(GLenum target = 0x%X, GLuint %d)", target, id);

+

+    try

+    {

+        switch(target)

+        {

+        case GL_ANY_SAMPLES_PASSED_EXT: 

+        case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:

+            break;

+        default: 

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(id == 0)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->beginQuery(target, id);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)

+{

+    TRACE("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(strncmp(name, "gl_", 3) == 0)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            programObject->bindAttributeLocation(index, name);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer)

+{

+    TRACE("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(target)

+            {

+              case GL_ARRAY_BUFFER:

+                context->bindArrayBuffer(buffer);

+                return;

+              case GL_ELEMENT_ARRAY_BUFFER:

+                context->bindElementArrayBuffer(buffer);

+                return;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer)

+{

+    TRACE("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);

+

+    try

+    {

+        if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)

+            {

+                context->bindReadFramebuffer(framebuffer);

+            }

+            

+            if(target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)

+            {

+                context->bindDrawFramebuffer(framebuffer);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer)

+{

+    TRACE("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);

+

+    try

+    {

+        if(target != GL_RENDERBUFFER)

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->bindRenderbuffer(renderbuffer);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBindTexture(GLenum target, GLuint texture)

+{

+    TRACE("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *textureObject = context->getTexture(texture);

+

+            if(textureObject && textureObject->getTarget() != target && texture != 0)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(target)

+            {

+            case GL_TEXTURE_2D:

+                context->bindTexture2D(texture);

+                return;

+            case GL_TEXTURE_CUBE_MAP:

+                context->bindTextureCubeMap(texture);

+                return;

+            case GL_TEXTURE_EXTERNAL_OES:

+                context->bindTextureExternal(texture);

+                return;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)

+{

+    TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",

+          red, green, blue, alpha);

+

+    try

+    {

+        gl::Context* context = gl::getContext();

+

+        if(context)

+        {

+            context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBlendEquation(GLenum mode)

+{

+    glBlendEquationSeparate(mode, mode);

+}

+

+void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)

+{

+    TRACE("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha);

+

+    try

+    {

+        switch(modeRGB)

+        {

+        case GL_FUNC_ADD:

+        case GL_FUNC_SUBTRACT:

+        case GL_FUNC_REVERSE_SUBTRACT:

+        case GL_MIN_EXT:

+        case GL_MAX_EXT:

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(modeAlpha)

+        {

+        case GL_FUNC_ADD:

+        case GL_FUNC_SUBTRACT:

+        case GL_FUNC_REVERSE_SUBTRACT:

+        case GL_MIN_EXT:

+        case GL_MAX_EXT:

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setBlendEquation(modeRGB, modeAlpha);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)

+{

+    glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);

+}

+

+void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)

+{

+    TRACE("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",

+          srcRGB, dstRGB, srcAlpha, dstAlpha);

+

+    try

+    {

+        switch(srcRGB)

+        {

+          case GL_ZERO:

+          case GL_ONE:

+          case GL_SRC_COLOR:

+          case GL_ONE_MINUS_SRC_COLOR:

+          case GL_DST_COLOR:

+          case GL_ONE_MINUS_DST_COLOR:

+          case GL_SRC_ALPHA:

+          case GL_ONE_MINUS_SRC_ALPHA:

+          case GL_DST_ALPHA:

+          case GL_ONE_MINUS_DST_ALPHA:

+          case GL_CONSTANT_COLOR:

+          case GL_ONE_MINUS_CONSTANT_COLOR:

+          case GL_CONSTANT_ALPHA:

+          case GL_ONE_MINUS_CONSTANT_ALPHA:

+          case GL_SRC_ALPHA_SATURATE:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(dstRGB)

+        {

+          case GL_ZERO:

+          case GL_ONE:

+          case GL_SRC_COLOR:

+          case GL_ONE_MINUS_SRC_COLOR:

+          case GL_DST_COLOR:

+          case GL_ONE_MINUS_DST_COLOR:

+          case GL_SRC_ALPHA:

+          case GL_ONE_MINUS_SRC_ALPHA:

+          case GL_DST_ALPHA:

+          case GL_ONE_MINUS_DST_ALPHA:

+          case GL_CONSTANT_COLOR:

+          case GL_ONE_MINUS_CONSTANT_COLOR:

+          case GL_CONSTANT_ALPHA:

+          case GL_ONE_MINUS_CONSTANT_ALPHA:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(srcAlpha)

+        {

+          case GL_ZERO:

+          case GL_ONE:

+          case GL_SRC_COLOR:

+          case GL_ONE_MINUS_SRC_COLOR:

+          case GL_DST_COLOR:

+          case GL_ONE_MINUS_DST_COLOR:

+          case GL_SRC_ALPHA:

+          case GL_ONE_MINUS_SRC_ALPHA:

+          case GL_DST_ALPHA:

+          case GL_ONE_MINUS_DST_ALPHA:

+          case GL_CONSTANT_COLOR:

+          case GL_ONE_MINUS_CONSTANT_COLOR:

+          case GL_CONSTANT_ALPHA:

+          case GL_ONE_MINUS_CONSTANT_ALPHA:

+          case GL_SRC_ALPHA_SATURATE:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(dstAlpha)

+        {

+          case GL_ZERO:

+          case GL_ONE:

+          case GL_SRC_COLOR:

+          case GL_ONE_MINUS_SRC_COLOR:

+          case GL_DST_COLOR:

+          case GL_ONE_MINUS_DST_COLOR:

+          case GL_SRC_ALPHA:

+          case GL_ONE_MINUS_SRC_ALPHA:

+          case GL_DST_ALPHA:

+          case GL_ONE_MINUS_DST_ALPHA:

+          case GL_CONSTANT_COLOR:

+          case GL_ONE_MINUS_CONSTANT_COLOR:

+          case GL_CONSTANT_ALPHA:

+          case GL_ONE_MINUS_CONSTANT_ALPHA:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)

+{

+    TRACE("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)",

+          target, size, data, usage);

+

+    try

+    {

+        if(size < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        switch(usage)

+        {

+          case GL_STREAM_DRAW:

+          case GL_STATIC_DRAW:

+          case GL_DYNAMIC_DRAW:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Buffer *buffer;

+

+            switch(target)

+            {

+              case GL_ARRAY_BUFFER:

+                buffer = context->getArrayBuffer();

+                break;

+              case GL_ELEMENT_ARRAY_BUFFER:

+                buffer = context->getElementArrayBuffer();

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(!buffer)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            buffer->bufferData(data, size, usage);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)

+{

+    TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)",

+          target, offset, size, data);

+

+    try

+    {

+        if(size < 0 || offset < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(data == NULL)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Buffer *buffer;

+

+            switch(target)

+            {

+              case GL_ARRAY_BUFFER:

+                buffer = context->getArrayBuffer();

+                break;

+              case GL_ELEMENT_ARRAY_BUFFER:

+                buffer = context->getElementArrayBuffer();

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(!buffer)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if((size_t)size + offset > buffer->size())

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            buffer->bufferSubData(data, size, offset);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target)

+{

+    TRACE("(GLenum target = 0x%X)", target);

+

+    try

+    {

+        if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)

+        {

+            return error(GL_INVALID_ENUM, 0);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Framebuffer *framebuffer = NULL;

+            if(target == GL_READ_FRAMEBUFFER_ANGLE)

+            {

+                framebuffer = context->getReadFramebuffer();

+            }

+            else

+            {

+                framebuffer = context->getDrawFramebuffer();

+            }

+

+            return framebuffer->completeness();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, 0);

+    }

+

+    return 0;

+}

+

+void GL_APIENTRY glClear(GLbitfield mask)

+{

+    TRACE("(GLbitfield mask = %X)", mask);

+

+    try

+    {

+		if((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)

+		{

+			return error(GL_INVALID_VALUE);

+		}

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->clear(mask);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)

+{

+    TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",

+          red, green, blue, alpha);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setClearColor(red, green, blue, alpha);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glClearDepthf(GLclampf depth)

+{

+    TRACE("(GLclampf depth = %f)", depth);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setClearDepth(depth);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glClearStencil(GLint s)

+{

+    TRACE("(GLint s = %d)", s);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setClearStencil(s);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)

+{

+    TRACE("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",

+          red, green, blue, alpha);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glCompileShader(GLuint shader)

+{

+    TRACE("(GLuint shader = %d)", shader);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!shaderObject)

+            {

+                if(context->getProgram(shader))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            shaderObject->compile();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, 

+                                        GLint border, GLsizei imageSize, const GLvoid* data)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " 

+          "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",

+          target, level, internalformat, width, height, border, imageSize, data);

+

+    try

+    {

+        if(!validImageSize(level, width, height) || border != 0 || imageSize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        switch(internalformat)

+        {

+        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:

+        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+			if(!S3TC_SUPPORT)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+		case GL_DEPTH_COMPONENT:

+		case GL_DEPTH_COMPONENT16:

+		case GL_DEPTH_COMPONENT32_OES:

+		case GL_DEPTH_STENCIL_OES:

+		case GL_DEPTH24_STENCIL8_OES:

+			return error(GL_INVALID_OPERATION);

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(border != 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+			if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            switch(target)

+            {

+              case GL_TEXTURE_2D:

+                if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||

+                    height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

+                if(width != height)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+

+                if(width > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||

+                   height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            if(target == GL_TEXTURE_2D)

+            {

+                gl::Texture2D *texture = context->getTexture2D();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                texture->setCompressedImage(level, internalformat, width, height, imageSize, data);

+            }

+            else

+            {

+                gl::TextureCubeMap *texture = context->getTextureCubeMap();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                switch(target)

+                {

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_X:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

+                    texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);

+                    break;

+                  default: UNREACHABLE();

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                         GLenum format, GLsizei imageSize, const GLvoid* data)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "

+          "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "

+          "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",

+          target, level, xoffset, yoffset, width, height, format, imageSize, data);

+

+    try

+    {

+        if(!gl::IsTextureTarget(target))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        switch(format)

+        {

+        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:

+        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+			if(!S3TC_SUPPORT)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(width == 0 || height == 0 || data == NULL)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            if(imageSize != gl::ComputeCompressedSize(width, height, format))

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            if(xoffset % 4 != 0 || yoffset % 4 != 0)

+            {

+				// We wait to check the offsets until this point, because the multiple-of-four restriction does not exist unless DXT1 textures are supported

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(target == GL_TEXTURE_2D)

+            {

+                gl::Texture2D *texture = context->getTexture2D();

+

+                if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, texture))

+				{

+					texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);

+				}

+            }

+            else if(gl::IsCubemapTextureTarget(target))

+            {

+                gl::TextureCubeMap *texture = context->getTextureCubeMap();

+

+                if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, texture))

+				{

+					texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);

+				}

+            }

+            else

+            {

+                UNREACHABLE();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "

+          "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",

+          target, level, internalformat, x, y, width, height, border);

+

+    try

+    {

+        if(!validImageSize(level, width, height))

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(border != 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(target)

+            {

+              case GL_TEXTURE_2D:

+                if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||

+                   height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

+                if(width != height)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+

+                if(width > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||

+                   height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            gl::Framebuffer *framebuffer = context->getReadFramebuffer();

+

+            if(framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)

+            {

+                return error(GL_INVALID_FRAMEBUFFER_OPERATION);

+            }

+

+            if(context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() > 1)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            gl::Renderbuffer *source = framebuffer->getColorbuffer();

+            GLenum colorbufferFormat = source->getFormat();

+

+            // [OpenGL ES 2.0.24] table 3.9

+            switch(internalformat)

+            {

+            case GL_ALPHA:

+                if(colorbufferFormat != GL_ALPHA &&

+                   colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                break;

+            case GL_LUMINANCE:

+            case GL_RGB:

+                if(colorbufferFormat != GL_RGB &&

+                   colorbufferFormat != GL_RGB565 &&

+                   colorbufferFormat != GL_RGB8_OES &&

+                   colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                break;

+            case GL_LUMINANCE_ALPHA:

+            case GL_RGBA:

+                if(colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                 {

+                     return error(GL_INVALID_OPERATION);

+                 }

+                 break;

+            case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:

+            case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+			case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+			case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+                if(S3TC_SUPPORT)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(target == GL_TEXTURE_2D)

+            {

+                gl::Texture2D *texture = context->getTexture2D();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                texture->copyImage(level, internalformat, x, y, width, height, framebuffer);

+            }

+            else if(gl::IsCubemapTextureTarget(target))

+            {

+                gl::TextureCubeMap *texture = context->getTextureCubeMap();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);

+            }

+            else UNREACHABLE();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "

+          "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",

+          target, level, xoffset, yoffset, x, y, width, height);

+

+    try

+    {

+        if(!gl::IsTextureTarget(target))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(width == 0 || height == 0)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            gl::Framebuffer *framebuffer = context->getReadFramebuffer();

+

+            if(framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)

+            {

+                return error(GL_INVALID_FRAMEBUFFER_OPERATION);

+            }

+

+            if(context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() > 1)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            gl::Renderbuffer *source = framebuffer->getColorbuffer();

+            GLenum colorbufferFormat = source->getFormat();

+            gl::Texture *texture = NULL;

+

+            if(target == GL_TEXTURE_2D)

+            {

+                texture = context->getTexture2D();

+            }

+            else if(gl::IsCubemapTextureTarget(target))

+            {

+                texture = context->getTextureCubeMap();

+            }

+            else UNREACHABLE();

+

+            if(!validateSubImageParams(false, width, height, xoffset, yoffset, target, level, GL_NONE, texture))

+			{

+				return;

+			}

+

+            GLenum textureFormat = texture->getFormat(target, level);

+

+            // [OpenGL ES 2.0.24] table 3.9

+            switch(textureFormat)

+            {

+            case GL_ALPHA:

+                if(colorbufferFormat != GL_ALPHA &&

+                   colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                break;

+            case GL_LUMINANCE:

+            case GL_RGB:

+                if(colorbufferFormat != GL_RGB &&

+                   colorbufferFormat != GL_RGB565 &&

+                   colorbufferFormat != GL_RGB8_OES &&

+                   colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                break;

+            case GL_LUMINANCE_ALPHA:

+            case GL_RGBA:

+                if(colorbufferFormat != GL_RGBA &&

+                   colorbufferFormat != GL_RGBA4 &&

+                   colorbufferFormat != GL_RGB5_A1 &&

+                   colorbufferFormat != GL_RGBA8_OES)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                break;

+            case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:

+            case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+			case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+			case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+                return error(GL_INVALID_OPERATION);

+			case GL_DEPTH_COMPONENT:

+			case GL_DEPTH_STENCIL_OES:

+				return error(GL_INVALID_OPERATION);

+            default:

+                return error(GL_INVALID_OPERATION);

+            }

+

+            texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);

+        }

+    }

+

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLuint GL_APIENTRY glCreateProgram(void)

+{

+    TRACE("()");

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            return context->createProgram();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, 0);

+    }

+

+    return 0;

+}

+

+GLuint GL_APIENTRY glCreateShader(GLenum type)

+{

+    TRACE("(GLenum type = 0x%X)", type);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(type)

+            {

+              case GL_FRAGMENT_SHADER:

+              case GL_VERTEX_SHADER:

+                return context->createShader(type);

+              default:

+                return error(GL_INVALID_ENUM, 0);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, 0);

+    }

+

+    return 0;

+}

+

+void GL_APIENTRY glCullFace(GLenum mode)

+{

+    TRACE("(GLenum mode = 0x%X)", mode);

+

+    try

+    {

+        switch(mode)

+        {

+          case GL_FRONT:

+          case GL_BACK:

+          case GL_FRONT_AND_BACK:

+            {

+                gl::Context *context = gl::getContext();

+

+                if(context)

+                {

+                    context->setCullMode(mode);

+                }

+            }

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers)

+{

+    TRACE("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                context->deleteBuffer(buffers[i]);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences)

+{

+    TRACE("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                context->deleteFence(fences[i]);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)

+{

+    TRACE("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                if(framebuffers[i] != 0)

+                {

+                    context->deleteFramebuffer(framebuffers[i]);

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteProgram(GLuint program)

+{

+    TRACE("(GLuint program = %d)", program);

+

+    try

+    {

+        if(program == 0)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(!context->getProgram(program))

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            context->deleteProgram(program);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids)

+{

+    TRACE("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                context->deleteQuery(ids[i]);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)

+{

+    TRACE("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                context->deleteRenderbuffer(renderbuffers[i]);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteShader(GLuint shader)

+{

+    TRACE("(GLuint shader = %d)", shader);

+

+    try

+    {

+        if(shader == 0)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(!context->getShader(shader))

+            {

+                if(context->getProgram(shader))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            context->deleteShader(shader);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)

+{

+    TRACE("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                if(textures[i] != 0)

+                {

+                    context->deleteTexture(textures[i]);

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDepthFunc(GLenum func)

+{

+    TRACE("(GLenum func = 0x%X)", func);

+

+    try

+    {

+        switch(func)

+        {

+          case GL_NEVER:

+          case GL_ALWAYS:

+          case GL_LESS:

+          case GL_LEQUAL:

+          case GL_EQUAL:

+          case GL_GREATER:

+          case GL_GEQUAL:

+          case GL_NOTEQUAL:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setDepthFunc(func);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDepthMask(GLboolean flag)

+{

+    TRACE("(GLboolean flag = %d)", flag);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setDepthMask(flag != GL_FALSE);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar)

+{

+    TRACE("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setDepthRange(zNear, zFar);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)

+{

+    TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+

+            gl::Program *programObject = context->getProgram(program);

+            gl::Shader *shaderObject = context->getShader(shader);

+            

+            if(!programObject)

+            {

+                gl::Shader *shaderByProgramHandle;

+                shaderByProgramHandle = context->getShader(program);

+                if(!shaderByProgramHandle)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                else

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+            }

+

+            if(!shaderObject)

+            {

+                gl::Program *programByShaderHandle = context->getProgram(shader);

+                if(!programByShaderHandle)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                else

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+            }

+

+            if(!programObject->detachShader(shaderObject))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDisable(GLenum cap)

+{

+    TRACE("(GLenum cap = 0x%X)", cap);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(cap)

+            {

+              case GL_CULL_FACE:                context->setCullFace(false);              break;

+              case GL_POLYGON_OFFSET_FILL:      context->setPolygonOffsetFill(false);     break;

+              case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break;

+              case GL_SAMPLE_COVERAGE:          context->setSampleCoverage(false);        break;

+              case GL_SCISSOR_TEST:             context->setScissorTest(false);           break;

+              case GL_STENCIL_TEST:             context->setStencilTest(false);           break;

+              case GL_DEPTH_TEST:               context->setDepthTest(false);             break;

+              case GL_BLEND:                    context->setBlend(false);                 break;

+              case GL_DITHER:                   context->setDither(false);                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDisableVertexAttribArray(GLuint index)

+{

+    TRACE("(GLuint index = %d)", index);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setEnableVertexAttribArray(index, false);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)

+{

+    TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count);

+

+    try

+    {

+        if(count < 0 || first < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->drawArrays(mode, first, count);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)

+{

+    TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)",

+          mode, count, type, indices);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(type)

+            {

+              case GL_UNSIGNED_BYTE:

+              case GL_UNSIGNED_SHORT:

+              case GL_UNSIGNED_INT:

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        

+            context->drawElements(mode, count, type, indices);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glEnable(GLenum cap)

+{

+    TRACE("(GLenum cap = 0x%X)", cap);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(cap)

+            {

+              case GL_CULL_FACE:                context->setCullFace(true);              break;

+              case GL_POLYGON_OFFSET_FILL:      context->setPolygonOffsetFill(true);     break;

+              case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break;

+              case GL_SAMPLE_COVERAGE:          context->setSampleCoverage(true);        break;

+              case GL_SCISSOR_TEST:             context->setScissorTest(true);           break;

+              case GL_STENCIL_TEST:             context->setStencilTest(true);           break;

+              case GL_DEPTH_TEST:               context->setDepthTest(true);             break;

+              case GL_BLEND:                    context->setBlend(true);                 break;

+              case GL_DITHER:                   context->setDither(true);                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glEnableVertexAttribArray(GLuint index)

+{

+    TRACE("(GLuint index = %d)", index);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setEnableVertexAttribArray(index, true);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glEndQueryEXT(GLenum target)

+{

+    TRACE("GLenum target = 0x%X)", target);

+

+    try

+    {

+        switch(target)

+        {

+        case GL_ANY_SAMPLES_PASSED_EXT: 

+        case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:

+            break;

+        default: 

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->endQuery(target);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFinishFenceNV(GLuint fence)

+{

+    TRACE("(GLuint fence = %d)", fence);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Fence* fenceObject = context->getFence(fence);

+

+            if(fenceObject == NULL)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            fenceObject->finishFence();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFinish(void)

+{

+    TRACE("()");

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->finish();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFlush(void)

+{

+    TRACE("()");

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->flush();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)

+{

+    TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "

+          "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);

+

+    try

+    {

+        if((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)

+            || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Framebuffer *framebuffer = NULL;

+            GLuint framebufferHandle = 0;

+            if(target == GL_READ_FRAMEBUFFER_ANGLE)

+            {

+                framebuffer = context->getReadFramebuffer();

+                framebufferHandle = context->getReadFramebufferHandle();

+            }

+            else

+            {

+                framebuffer = context->getDrawFramebuffer();

+                framebufferHandle = context->getDrawFramebufferHandle();

+            }

+

+            if(!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(attachment)

+            {

+              case GL_COLOR_ATTACHMENT0:

+                framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer);

+                break;

+              case GL_DEPTH_ATTACHMENT:

+                framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);

+                break;

+              case GL_STENCIL_ATTACHMENT:

+                framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)

+{

+    TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "

+          "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);

+

+    try

+    {

+        if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(attachment)

+        {

+          case GL_COLOR_ATTACHMENT0:

+          case GL_DEPTH_ATTACHMENT:

+          case GL_STENCIL_ATTACHMENT:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(texture == 0)

+            {

+                textarget = GL_NONE;

+            }

+            else

+            {

+                gl::Texture *tex = context->getTexture(texture);

+

+                if(tex == NULL)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                if(tex->isCompressed(textarget, level))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                switch(textarget)

+                {

+                  case GL_TEXTURE_2D:

+                    if(tex->getTarget() != GL_TEXTURE_2D)

+                    {

+                        return error(GL_INVALID_OPERATION);

+                    }

+                    break;

+

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_X:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:

+                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:

+                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

+                    if(tex->getTarget() != GL_TEXTURE_CUBE_MAP)

+                    {

+                        return error(GL_INVALID_OPERATION);

+                    }

+                    break;

+

+                  default:

+                    return error(GL_INVALID_ENUM);

+                }

+

+                if(level != 0)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            gl::Framebuffer *framebuffer = NULL;

+            GLuint framebufferHandle = 0;

+            if(target == GL_READ_FRAMEBUFFER_ANGLE)

+            {

+                framebuffer = context->getReadFramebuffer();

+                framebufferHandle = context->getReadFramebufferHandle();

+            }

+            else

+            {

+                framebuffer = context->getDrawFramebuffer();

+                framebufferHandle = context->getDrawFramebufferHandle();

+            }

+

+            if(framebufferHandle == 0 || !framebuffer)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(attachment)

+            {

+              case GL_COLOR_ATTACHMENT0:  framebuffer->setColorbuffer(textarget, texture);   break;

+              case GL_DEPTH_ATTACHMENT:   framebuffer->setDepthbuffer(textarget, texture);   break;

+              case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glFrontFace(GLenum mode)

+{

+    TRACE("(GLenum mode = 0x%X)", mode);

+

+    try

+    {

+        switch(mode)

+        {

+          case GL_CW:

+          case GL_CCW:

+            {

+                gl::Context *context = gl::getContext();

+

+                if(context)

+                {

+                    context->setFrontFace(mode);

+                }

+            }

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers)

+{

+    TRACE("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                buffers[i] = context->createBuffer();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenerateMipmap(GLenum target)

+{

+    TRACE("(GLenum target = 0x%X)", target);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *texture;

+

+            switch(target)

+            {

+              case GL_TEXTURE_2D:

+                texture = context->getTexture2D();

+                break;

+              case GL_TEXTURE_CUBE_MAP:

+                texture = context->getTextureCubeMap();

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(texture->isCompressed(target, 0) || texture->isDepth(target, 0))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            texture->generateMipmaps();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences)

+{

+    TRACE("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                fences[i] = context->createFence();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers)

+{

+    TRACE("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                framebuffers[i] = context->createFramebuffer();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids)

+{

+    TRACE("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                ids[i] = context->createQuery();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)

+{

+    TRACE("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                renderbuffers[i] = context->createRenderbuffer();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures)

+{

+    TRACE("(GLsizei n = %d, GLuint* textures =  0x%0.8p)", n, textures);

+

+    try

+    {

+        if(n < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            for(int i = 0; i < n; i++)

+            {

+                textures[i] = context->createTexture();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)

+{

+    TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, "

+          "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)",

+          program, index, bufsize, length, size, type, name);

+

+    try

+    {

+        if(bufsize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(index >= (GLuint)programObject->getActiveAttributeCount())

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            programObject->getActiveAttribute(index, bufsize, length, size, type, name);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)

+{

+    TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, "

+          "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)",

+          program, index, bufsize, length, size, type, name);

+

+    try

+    {

+        if(bufsize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(index >= (GLuint)programObject->getActiveUniformCount())

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            programObject->getActiveUniform(index, bufsize, length, size, type, name);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)

+{

+    TRACE("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)",

+          program, maxcount, count, shaders);

+

+    try

+    {

+        if(maxcount < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            return programObject->getAttachedShaders(maxcount, count, shaders);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+int GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name)

+{

+    TRACE("(GLuint program = %d, const GLchar* name = %s)", program, name);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION, -1);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE, -1);

+                }

+            }

+

+            if(!programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION, -1);

+            }

+

+            return programObject->getAttributeLocation(name);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, -1);

+    }

+

+    return -1;

+}

+

+void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params)

+{

+    TRACE("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)",  pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(!(context->getBooleanv(pname, params)))

+            {

+                GLenum nativeType;

+                unsigned int numParams = 0;

+                if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))

+                    return error(GL_INVALID_ENUM);

+

+                if(numParams == 0)

+                    return; // it is known that the pname is valid, but there are no parameters to return

+

+                if(nativeType == GL_FLOAT)

+                {

+                    GLfloat *floatParams = NULL;

+                    floatParams = new GLfloat[numParams];

+

+                    context->getFloatv(pname, floatParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        if(floatParams[i] == 0.0f)

+                            params[i] = GL_FALSE;

+                        else

+                            params[i] = GL_TRUE;

+                    }

+

+                    delete [] floatParams;

+                }

+                else if(nativeType == GL_INT)

+                {

+                    GLint *intParams = NULL;

+                    intParams = new GLint[numParams];

+

+                    context->getIntegerv(pname, intParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        if(intParams[i] == 0)

+                            params[i] = GL_FALSE;

+                        else

+                            params[i] = GL_TRUE;

+                    }

+

+                    delete [] intParams;

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Buffer *buffer;

+

+            switch(target)

+            {

+              case GL_ARRAY_BUFFER:

+                buffer = context->getArrayBuffer();

+                break;

+              case GL_ELEMENT_ARRAY_BUFFER:

+                buffer = context->getElementArrayBuffer();

+                break;

+              default: return error(GL_INVALID_ENUM);

+            }

+

+            if(!buffer)

+            {

+                // A null buffer means that "0" is bound to the requested buffer target

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(pname)

+            {

+              case GL_BUFFER_USAGE:

+                *params = buffer->usage();

+                break;

+              case GL_BUFFER_SIZE:

+                *params = buffer->size();

+                break;

+              default: return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLenum GL_APIENTRY glGetError(void)

+{

+    TRACE("()");

+

+    gl::Context *context = gl::getContext();

+

+    if(context)

+    {

+        return context->getError();

+    }

+

+    return GL_NO_ERROR;

+}

+

+void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)

+{

+    TRACE("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Fence *fenceObject = context->getFence(fence);

+

+            if(fenceObject == NULL)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            fenceObject->getFenceiv(pname, params);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params)

+{

+    TRACE("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(!(context->getFloatv(pname, params)))

+            {

+                GLenum nativeType;

+                unsigned int numParams = 0;

+                if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))

+                    return error(GL_INVALID_ENUM);

+

+                if(numParams == 0)

+                    return; // it is known that the pname is valid, but that there are no parameters to return.

+

+                if(nativeType == GL_BOOL)

+                {

+                    GLboolean *boolParams = NULL;

+                    boolParams = new GLboolean[numParams];

+

+                    context->getBooleanv(pname, boolParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        if(boolParams[i] == GL_FALSE)

+                            params[i] = 0.0f;

+                        else

+                            params[i] = 1.0f;

+                    }

+

+                    delete [] boolParams;

+                }

+                else if(nativeType == GL_INT)

+                {

+                    GLint *intParams = NULL;

+                    intParams = new GLint[numParams];

+

+                    context->getIntegerv(pname, intParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        params[i] = (GLfloat)intParams[i];

+                    }

+

+                    delete [] intParams;

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)

+{

+    TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",

+          target, attachment, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+

+            gl::Framebuffer *framebuffer = NULL;

+            if(target == GL_READ_FRAMEBUFFER_ANGLE)

+            {

+                if(context->getReadFramebufferHandle() == 0)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                framebuffer = context->getReadFramebuffer();

+            }

+            else 

+            {

+                if(context->getDrawFramebufferHandle() == 0)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                framebuffer = context->getDrawFramebuffer();

+            }

+

+            GLenum attachmentType;

+            GLuint attachmentHandle;

+            switch(attachment)

+            {

+              case GL_COLOR_ATTACHMENT0:    

+                attachmentType = framebuffer->getColorbufferType();

+                attachmentHandle = framebuffer->getColorbufferHandle(); 

+                break;

+              case GL_DEPTH_ATTACHMENT:     

+                attachmentType = framebuffer->getDepthbufferType();

+                attachmentHandle = framebuffer->getDepthbufferHandle();

+                break;

+              case GL_STENCIL_ATTACHMENT:   

+                attachmentType = framebuffer->getStencilbufferType();

+                attachmentHandle = framebuffer->getStencilbufferHandle();

+                break;

+              default: return error(GL_INVALID_ENUM);

+            }

+

+            GLenum attachmentObjectType;   // Type category

+            if(attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER)

+            {

+                attachmentObjectType = attachmentType;

+            }

+            else if(gl::IsTextureTarget(attachmentType))

+            {

+                attachmentObjectType = GL_TEXTURE;

+            }

+            else UNREACHABLE();

+

+            switch(pname)

+            {

+              case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:

+                *params = attachmentObjectType;

+                break;

+              case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:

+                if(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)

+                {

+                    *params = attachmentHandle;

+                }

+                else

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+              case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:

+                if(attachmentObjectType == GL_TEXTURE)

+                {

+                    *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0

+                }

+                else

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+              case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:

+                if(attachmentObjectType == GL_TEXTURE)

+                {

+                    if(gl::IsCubemapTextureTarget(attachmentType))

+                    {

+                        *params = attachmentType;

+                    }

+                    else

+                    {

+                        *params = 0;

+                    }

+                }

+                else

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void)

+{

+    TRACE("()");

+

+    return GL_NO_ERROR;

+}

+

+void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params)

+{

+    TRACE("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(!(context->getIntegerv(pname, params)))

+            {

+                GLenum nativeType;

+                unsigned int numParams = 0;

+                if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))

+                    return error(GL_INVALID_ENUM);

+

+                if(numParams == 0)

+                    return; // it is known that pname is valid, but there are no parameters to return

+

+                if(nativeType == GL_BOOL)

+                {

+                    GLboolean *boolParams = NULL;

+                    boolParams = new GLboolean[numParams];

+

+                    context->getBooleanv(pname, boolParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        if(boolParams[i] == GL_FALSE)

+                            params[i] = 0;

+                        else

+                            params[i] = 1;

+                    }

+

+                    delete [] boolParams;

+                }

+                else if(nativeType == GL_FLOAT)

+                {

+                    GLfloat *floatParams = NULL;

+                    floatParams = new GLfloat[numParams];

+

+                    context->getFloatv(pname, floatParams);

+

+                    for(unsigned int i = 0; i < numParams; ++i)

+                    {

+                        if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)

+                        {

+                            params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f);

+                        }

+                        else

+                            params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));

+                    }

+

+                    delete [] floatParams;

+                }

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params)

+{

+    TRACE("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            switch(pname)

+            {

+              case GL_DELETE_STATUS:

+                *params = programObject->isFlaggedForDeletion();

+                return;

+              case GL_LINK_STATUS:

+                *params = programObject->isLinked();

+                return;

+              case GL_VALIDATE_STATUS:

+                *params = programObject->isValidated();

+                return;

+              case GL_INFO_LOG_LENGTH:

+                *params = programObject->getInfoLogLength();

+                return;

+              case GL_ATTACHED_SHADERS:

+                *params = programObject->getAttachedShadersCount();

+                return;

+              case GL_ACTIVE_ATTRIBUTES:

+                *params = programObject->getActiveAttributeCount();

+                return;

+              case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:

+                *params = programObject->getActiveAttributeMaxLength();

+                return;

+              case GL_ACTIVE_UNIFORMS:

+                *params = programObject->getActiveUniformCount();

+                return;

+              case GL_ACTIVE_UNIFORM_MAX_LENGTH:

+                *params = programObject->getActiveUniformMaxLength();

+                return;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)

+{

+    TRACE("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",

+          program, bufsize, length, infolog);

+

+    try

+    {

+        if(bufsize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            programObject->getInfoLog(bufsize, length, infolog);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)

+{

+    TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params);

+

+    try

+    {

+        switch(pname)

+        {

+        case GL_CURRENT_QUERY_EXT:

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            params[0] = context->getActiveQuery(target);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)

+{

+    TRACE("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);

+

+    try

+    {

+        switch(pname)

+        {

+        case GL_QUERY_RESULT_EXT:

+        case GL_QUERY_RESULT_AVAILABLE_EXT:

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Query *queryObject = context->getQuery(id, false, GL_NONE);

+

+            if(!queryObject)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(context->getActiveQuery(queryObject->getType()) == id)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(pname)

+            {

+            case GL_QUERY_RESULT_EXT:

+                params[0] = queryObject->getResult();

+                break;

+            case GL_QUERY_RESULT_AVAILABLE_EXT:

+                params[0] = queryObject->isResultAvailable();

+                break;

+            default:

+                ASSERT(false);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(target != GL_RENDERBUFFER)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(context->getRenderbufferHandle() == 0)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle());

+

+            switch(pname)

+            {

+            case GL_RENDERBUFFER_WIDTH:           *params = renderbuffer->getWidth();       break;

+            case GL_RENDERBUFFER_HEIGHT:          *params = renderbuffer->getHeight();      break;

+            case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getFormat();      break;

+            case GL_RENDERBUFFER_RED_SIZE:        *params = renderbuffer->getRedSize();     break;

+            case GL_RENDERBUFFER_GREEN_SIZE:      *params = renderbuffer->getGreenSize();   break;

+            case GL_RENDERBUFFER_BLUE_SIZE:       *params = renderbuffer->getBlueSize();    break;

+            case GL_RENDERBUFFER_ALPHA_SIZE:      *params = renderbuffer->getAlphaSize();   break;

+            case GL_RENDERBUFFER_DEPTH_SIZE:      *params = renderbuffer->getDepthSize();   break;

+            case GL_RENDERBUFFER_STENCIL_SIZE:    *params = renderbuffer->getStencilSize(); break;

+            case GL_RENDERBUFFER_SAMPLES_ANGLE:   *params = renderbuffer->getSamples();     break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)

+{

+    TRACE("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!shaderObject)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            switch(pname)

+            {

+              case GL_SHADER_TYPE:

+                *params = shaderObject->getType();

+                return;

+              case GL_DELETE_STATUS:

+                *params = shaderObject->isFlaggedForDeletion();

+                return;

+              case GL_COMPILE_STATUS:

+                *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;

+                return;

+              case GL_INFO_LOG_LENGTH:

+                *params = shaderObject->getInfoLogLength();

+                return;

+              case GL_SHADER_SOURCE_LENGTH:

+                *params = shaderObject->getSourceLength();

+                return;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)

+{

+    TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",

+          shader, bufsize, length, infolog);

+

+    try

+    {

+        if(bufsize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!shaderObject)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            shaderObject->getInfoLog(bufsize, length, infolog);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)

+{

+    TRACE("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)",

+          shadertype, precisiontype, range, precision);

+

+    try

+    {

+        switch(shadertype)

+        {

+          case GL_VERTEX_SHADER:

+          case GL_FRAGMENT_SHADER:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(precisiontype)

+        {

+          case GL_LOW_FLOAT:

+          case GL_MEDIUM_FLOAT:

+          case GL_HIGH_FLOAT:

+            // IEEE 754 single-precision

+            range[0] = 127;

+            range[1] = 127;

+            *precision = 23;

+            break;

+          case GL_LOW_INT:

+          case GL_MEDIUM_INT:

+          case GL_HIGH_INT:

+            // Single-precision floating-point numbers can accurately represent integers up to +/-16777216

+            range[0] = 24;

+            range[1] = 24;

+            *precision = 0;

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)

+{

+    TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",

+          shader, bufsize, length, source);

+

+    try

+    {

+        if(bufsize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!shaderObject)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            shaderObject->getSource(bufsize, length, source);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+const GLubyte* GL_APIENTRY glGetString(GLenum name)

+{

+    TRACE("(GLenum name = 0x%X)", name);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        switch(name)

+        {

+        case GL_VENDOR:

+            return (GLubyte*)"TransGaming Inc.";

+        case GL_RENDERER:

+            return (GLubyte*)"SwiftShader";

+        case GL_VERSION:

+            return (GLubyte*)"OpenGL ES 2.0 SwiftShader "VERSION_STRING;

+        case GL_SHADING_LANGUAGE_VERSION:

+            return (GLubyte*)"OpenGL ES GLSL ES 1.00 SwiftShader "VERSION_STRING;

+        case GL_EXTENSIONS:

+            // Keep list sorted in following order:

+	        // OES extensions

+	        // EXT extensions

+	        // Vendor extensions

+            return (GLubyte*)

+                "GL_OES_depth_texture "

+                "GL_OES_depth_texture_cube_map "

+                "GL_OES_EGL_image_external "

+                "GL_OES_element_index_uint "

+                "GL_OES_packed_depth_stencil "

+                "GL_OES_rgb8_rgba8 "

+                "GL_OES_standard_derivatives "

+                "GL_OES_texture_float "

+                "GL_OES_texture_float_linear "

+                "GL_OES_texture_half_float "

+                "GL_OES_texture_half_float_linear "

+                "GL_OES_texture_npot "

+                "GL_EXT_blend_minmax "

+                "GL_EXT_occlusion_query_boolean "

+                "GL_EXT_read_format_bgra "

+                   #if (S3TC_SUPPORT)

+                "GL_EXT_texture_compression_dxt1 "

+                "GL_ANGLE_texture_compression_dxt3 "

+                "GL_ANGLE_texture_compression_dxt5 "

+                   #endif

+                "GL_EXT_texture_filter_anisotropic "

+                "GL_EXT_texture_format_BGRA8888 "

+                "GL_ANGLE_framebuffer_blit "

+                "GL_ANGLE_framebuffer_multisample "

+                "GL_NV_fence";

+        default:

+            return error(GL_INVALID_ENUM, (GLubyte*)NULL);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL);

+    }

+

+    return NULL;

+}

+

+void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *texture;

+

+            switch(target)

+            {

+            case GL_TEXTURE_2D:

+                texture = context->getTexture2D();

+                break;

+            case GL_TEXTURE_CUBE_MAP:

+                texture = context->getTextureCubeMap();

+                break;

+            case GL_TEXTURE_EXTERNAL_OES:

+                texture = context->getTextureExternal();

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            switch(pname)

+            {

+            case GL_TEXTURE_MAG_FILTER:

+                *params = (GLfloat)texture->getMagFilter();

+                break;

+            case GL_TEXTURE_MIN_FILTER:

+                *params = (GLfloat)texture->getMinFilter();

+                break;

+            case GL_TEXTURE_WRAP_S:

+                *params = (GLfloat)texture->getWrapS();

+                break;

+            case GL_TEXTURE_WRAP_T:

+                *params = (GLfloat)texture->getWrapT();

+                break;

+			case GL_TEXTURE_MAX_ANISOTROPY_EXT:

+                *params = texture->getMaxAnisotropy();

+                break;

+            case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:

+                *params = (GLfloat)1;

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *texture;

+

+            switch(target)

+            {

+            case GL_TEXTURE_2D:

+                texture = context->getTexture2D();

+                break;

+            case GL_TEXTURE_CUBE_MAP:

+                texture = context->getTextureCubeMap();

+                break;

+            case GL_TEXTURE_EXTERNAL_OES:

+                texture = context->getTextureExternal();

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            switch(pname)

+            {

+            case GL_TEXTURE_MAG_FILTER:

+                *params = texture->getMagFilter();

+                break;

+            case GL_TEXTURE_MIN_FILTER:

+                *params = texture->getMinFilter();

+                break;

+            case GL_TEXTURE_WRAP_S:

+                *params = texture->getWrapS();

+                break;

+            case GL_TEXTURE_WRAP_T:

+                *params = texture->getWrapT();

+                break;

+		    case GL_TEXTURE_MAX_ANISOTROPY_EXT:

+                *params = (GLint)texture->getMaxAnisotropy();

+                break;

+            case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:

+                *params = 1;

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)

+{

+    TRACE("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)",

+          program, location, bufSize, params);

+

+    try

+    {

+        if(bufSize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(program == 0)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject || !programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject->getUniformfv(location, &bufSize, params))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)

+{

+    TRACE("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(program == 0)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject || !programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject->getUniformfv(location, NULL, params))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)

+{

+    TRACE("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", 

+          program, location, bufSize, params);

+

+    try

+    {

+        if(bufSize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(program == 0)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject || !programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject->getUniformiv(location, &bufSize, params))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)

+{

+    TRACE("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(program == 0)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject || !programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!programObject->getUniformiv(location, NULL, params))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name)

+{

+    TRACE("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(strstr(name, "gl_") == name)

+        {

+            return -1;

+        }

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION, -1);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE, -1);

+                }

+            }

+

+            if(!programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION, -1);

+            }

+

+            return programObject->getUniformLocation(name);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, -1);

+    }

+

+    return -1;

+}

+

+void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)

+{

+    TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(index >= gl::MAX_VERTEX_ATTRIBS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            const gl::VertexAttribute &attribState = context->getVertexAttribState(index);

+

+            switch(pname)

+            {

+              case GL_VERTEX_ATTRIB_ARRAY_ENABLED:

+                *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_SIZE:

+                *params = (GLfloat)attribState.mSize;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_STRIDE:

+                *params = (GLfloat)attribState.mStride;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_TYPE:

+                *params = (GLfloat)attribState.mType;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:

+                *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE);

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:

+                *params = (GLfloat)attribState.mBoundBuffer.id();

+                break;

+              case GL_CURRENT_VERTEX_ATTRIB:

+                for(int i = 0; i < 4; ++i)

+                {

+                    params[i] = attribState.mCurrentValue[i];

+                }

+                break;

+              default: return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)

+{

+    TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(index >= gl::MAX_VERTEX_ATTRIBS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            const gl::VertexAttribute &attribState = context->getVertexAttribState(index);

+

+            switch(pname)

+            {

+              case GL_VERTEX_ATTRIB_ARRAY_ENABLED:

+                *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_SIZE:

+                *params = attribState.mSize;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_STRIDE:

+                *params = attribState.mStride;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_TYPE:

+                *params = attribState.mType;

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:

+                *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);

+                break;

+              case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:

+                *params = attribState.mBoundBuffer.id();

+                break;

+              case GL_CURRENT_VERTEX_ATTRIB:

+                for(int i = 0; i < 4; ++i)

+                {

+                    float currentValue = attribState.mCurrentValue[i];

+                    params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));

+                }

+                break;

+              default: return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)

+{

+    TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(index >= gl::MAX_VERTEX_ATTRIBS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            if(pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)

+            {

+                return error(GL_INVALID_ENUM);

+            }

+

+            *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index));

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glHint(GLenum target, GLenum mode)

+{

+    TRACE("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode);

+

+    try

+    {

+        switch(mode)

+        {

+          case GL_FASTEST:

+          case GL_NICEST:

+          case GL_DONT_CARE:

+            break;

+          default:

+            return error(GL_INVALID_ENUM); 

+        }

+

+        gl::Context *context = gl::getContext();

+        switch(target)

+        {

+          case GL_GENERATE_MIPMAP_HINT:

+            if(context) context->setGenerateMipmapHint(mode);

+            break;

+          case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:

+            if(context) context->setFragmentShaderDerivativeHint(mode);

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLboolean GL_APIENTRY glIsBuffer(GLuint buffer)

+{

+    TRACE("(GLuint buffer = %d)", buffer);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && buffer)

+        {

+            gl::Buffer *bufferObject = context->getBuffer(buffer);

+

+            if(bufferObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsEnabled(GLenum cap)

+{

+    TRACE("(GLenum cap = 0x%X)", cap);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(cap)

+            {

+              case GL_CULL_FACE:                return context->isCullFaceEnabled();

+              case GL_POLYGON_OFFSET_FILL:      return context->isPolygonOffsetFillEnabled();

+              case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled();

+              case GL_SAMPLE_COVERAGE:          return context->isSampleCoverageEnabled();

+              case GL_SCISSOR_TEST:             return context->isScissorTestEnabled();

+              case GL_STENCIL_TEST:             return context->isStencilTestEnabled();

+              case GL_DEPTH_TEST:               return context->isDepthTestEnabled();

+              case GL_BLEND:                    return context->isBlendEnabled();

+              case GL_DITHER:                   return context->isDitherEnabled();

+              default:

+                return error(GL_INVALID_ENUM, false);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, false);

+    }

+

+    return false;

+}

+

+GLboolean GL_APIENTRY glIsFenceNV(GLuint fence)

+{

+    TRACE("(GLuint fence = %d)", fence);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Fence *fenceObject = context->getFence(fence);

+

+            if(fenceObject == NULL)

+            {

+                return GL_FALSE;

+            }

+

+            return fenceObject->isFence();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer)

+{

+    TRACE("(GLuint framebuffer = %d)", framebuffer);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && framebuffer)

+        {

+            gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);

+

+            if(framebufferObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsProgram(GLuint program)

+{

+    TRACE("(GLuint program = %d)", program);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && program)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(programObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsQueryEXT(GLuint id)

+{

+    TRACE("(GLuint id = %d)", id);

+

+    try

+    {

+        if(id == 0)

+        {

+            return GL_FALSE;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Query *queryObject = context->getQuery(id, false, GL_NONE);

+

+            if(queryObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer)

+{

+    TRACE("(GLuint renderbuffer = %d)", renderbuffer);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && renderbuffer)

+        {

+            gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);

+

+            if(renderbufferObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsShader(GLuint shader)

+{

+    TRACE("(GLuint shader = %d)", shader);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && shader)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(shaderObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+GLboolean GL_APIENTRY glIsTexture(GLuint texture)

+{

+    TRACE("(GLuint texture = %d)", texture);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context && texture)

+        {

+            gl::Texture *textureObject = context->getTexture(texture);

+

+            if(textureObject)

+            {

+                return GL_TRUE;

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY, GL_FALSE);

+    }

+

+    return GL_FALSE;

+}

+

+void GL_APIENTRY glLineWidth(GLfloat width)

+{

+    TRACE("(GLfloat width = %f)", width);

+

+    try

+    {

+        if(width <= 0.0f)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setLineWidth(width);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glLinkProgram(GLuint program)

+{

+    TRACE("(GLuint program = %d)", program);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            programObject->link();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glPixelStorei(GLenum pname, GLint param)

+{

+    TRACE("(GLenum pname = 0x%X, GLint param = %d)", pname, param);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(pname)

+            {

+              case GL_UNPACK_ALIGNMENT:

+                if(param != 1 && param != 2 && param != 4 && param != 8)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+

+                context->setUnpackAlignment(param);

+                break;

+

+              case GL_PACK_ALIGNMENT:

+                if(param != 1 && param != 2 && param != 4 && param != 8)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+

+                context->setPackAlignment(param);

+                break;

+

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units)

+{

+    TRACE("(GLfloat factor = %f, GLfloat units = %f)", factor, units);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setPolygonOffsetParams(factor, units);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,

+                                GLenum format, GLenum type, GLsizei bufSize,

+                                GLvoid *data)

+{

+    TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "

+          "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)",

+          x, y, width, height, format, type, bufSize, data);

+

+    try

+    {

+        if(width < 0 || height < 0 || bufSize < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(!validReadFormatType(format, type))

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->readPixels(x, y, width, height, format, type, &bufSize, data);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)

+{

+    TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "

+          "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)",

+          x, y, width, height, format, type,  pixels);

+

+    try

+    {

+        if(width < 0 || height < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(!validReadFormatType(format, type))

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->readPixels(x, y, width, height, format, type, NULL, pixels);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glReleaseShaderCompiler(void)

+{

+    TRACE("()");

+

+    try

+    {

+        gl::Shader::releaseCompiler();

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)

+{

+    TRACE("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",

+          target, samples, internalformat, width, height);

+

+    try

+    {

+        switch(target)

+        {

+          case GL_RENDERBUFFER:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(width < 0 || height < 0 || samples < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(width > gl::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || 

+               height > gl::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||

+               samples > gl::IMPLEMENTATION_MAX_SAMPLES)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            GLuint handle = context->getRenderbufferHandle();

+            if(handle == 0)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            switch(internalformat)

+            {

+              case GL_DEPTH_COMPONENT16:

+                context->setRenderbufferStorage(new gl::Depthbuffer(width, height, samples));

+                break;

+              case GL_RGBA4:

+              case GL_RGB5_A1:

+              case GL_RGB565:

+              case GL_RGB8_OES:

+              case GL_RGBA8_OES:

+                context->setRenderbufferStorage(new gl::Colorbuffer(width, height, internalformat, samples));

+                break;

+              case GL_STENCIL_INDEX8:

+                context->setRenderbufferStorage(new gl::Stencilbuffer(width, height, samples));

+                break;

+              case GL_DEPTH24_STENCIL8_OES:

+                context->setRenderbufferStorage(new gl::DepthStencilbuffer(width, height, samples));

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)

+{

+    glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height);

+}

+

+void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert)

+{

+    TRACE("(GLclampf value = %f, GLboolean invert = %d)", value, invert);

+

+    try

+    {

+        gl::Context* context = gl::getContext();

+

+        if(context)

+        {

+            context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition)

+{

+    TRACE("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition);

+

+    try

+    {

+        if(condition != GL_ALL_COMPLETED_NV)

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Fence *fenceObject = context->getFence(fence);

+

+            if(fenceObject == NULL)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            fenceObject->setFence(condition);    

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height)

+{

+    TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);

+

+    try

+    {

+        if(width < 0 || height < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context* context = gl::getContext();

+

+        if(context)

+        {

+            context->setScissorParams(x, y, width, height);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)

+{

+    TRACE("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, "

+          "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)",

+          n, shaders, binaryformat, binary, length);

+

+    try

+    {

+        // No binary shader formats are supported.

+        return error(GL_INVALID_ENUM);

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)

+{

+    TRACE("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)",

+          shader, count, string, length);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Shader *shaderObject = context->getShader(shader);

+

+            if(!shaderObject)

+            {

+                if(context->getProgram(shader))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            shaderObject->setSource(count, string, length);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask)

+{

+    glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);

+}

+

+void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)

+{

+    TRACE("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);

+

+    try

+    {

+        switch(face)

+        {

+          case GL_FRONT:

+          case GL_BACK:

+          case GL_FRONT_AND_BACK:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(func)

+        {

+          case GL_NEVER:

+          case GL_ALWAYS:

+          case GL_LESS:

+          case GL_LEQUAL:

+          case GL_EQUAL:

+          case GL_GEQUAL:

+          case GL_GREATER:

+          case GL_NOTEQUAL:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(face == GL_FRONT || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilParams(func, ref, mask);

+            }

+

+            if(face == GL_BACK || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilBackParams(func, ref, mask);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glStencilMask(GLuint mask)

+{

+    glStencilMaskSeparate(GL_FRONT_AND_BACK, mask);

+}

+

+void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask)

+{

+    TRACE("(GLenum face = 0x%X, GLuint mask = %d)", face, mask);

+

+    try

+    {

+        switch(face)

+        {

+          case GL_FRONT:

+          case GL_BACK:

+          case GL_FRONT_AND_BACK:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(face == GL_FRONT || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilWritemask(mask);

+            }

+

+            if(face == GL_BACK || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilBackWritemask(mask);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)

+{

+    glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);

+}

+

+void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)

+{

+    TRACE("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",

+          face, fail, zfail, zpass);

+

+    try

+    {

+        switch(face)

+        {

+          case GL_FRONT:

+          case GL_BACK:

+          case GL_FRONT_AND_BACK:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(fail)

+        {

+          case GL_ZERO:

+          case GL_KEEP:

+          case GL_REPLACE:

+          case GL_INCR:

+          case GL_DECR:

+          case GL_INVERT:

+          case GL_INCR_WRAP:

+          case GL_DECR_WRAP:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(zfail)

+        {

+          case GL_ZERO:

+          case GL_KEEP:

+          case GL_REPLACE:

+          case GL_INCR:

+          case GL_DECR:

+          case GL_INVERT:

+          case GL_INCR_WRAP:

+          case GL_DECR_WRAP:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        switch(zpass)

+        {

+          case GL_ZERO:

+          case GL_KEEP:

+          case GL_REPLACE:

+          case GL_INCR:

+          case GL_DECR:

+          case GL_INVERT:

+          case GL_INCR_WRAP:

+          case GL_DECR_WRAP:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(face == GL_FRONT || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilOperations(fail, zfail, zpass);

+            }

+

+            if(face == GL_BACK || face == GL_FRONT_AND_BACK)

+            {

+                context->setStencilBackOperations(fail, zfail, zpass);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+GLboolean GL_APIENTRY glTestFenceNV(GLuint fence)

+{

+    TRACE("(GLuint fence = %d)", fence);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Fence *fenceObject = context->getFence(fence);

+

+            if(fenceObject == NULL)

+            {

+                return error(GL_INVALID_OPERATION, GL_TRUE);

+            }

+

+            return fenceObject->testFence();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        error(GL_OUT_OF_MEMORY);

+    }

+    

+    return GL_TRUE;

+}

+

+void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,

+                              GLint border, GLenum format, GLenum type, const GLvoid* pixels)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "

+          "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels =  0x%0.8p)",

+          target, level, internalformat, width, height, border, format, type, pixels);

+

+    try

+    {

+        if(!validImageSize(level, width, height))

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(internalformat != format)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        switch(format)

+        {

+        case GL_ALPHA:

+        case GL_LUMINANCE:

+        case GL_LUMINANCE_ALPHA:

+            switch(type)

+            {

+            case GL_UNSIGNED_BYTE:

+            case GL_FLOAT:

+            case GL_HALF_FLOAT_OES:

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+        case GL_RGB:

+            switch(type)

+            {

+            case GL_UNSIGNED_BYTE:

+            case GL_UNSIGNED_SHORT_5_6_5:

+            case GL_FLOAT:

+            case GL_HALF_FLOAT_OES:

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+        case GL_RGBA:

+            switch(type)

+            {

+            case GL_UNSIGNED_BYTE:

+            case GL_UNSIGNED_SHORT_4_4_4_4:

+            case GL_UNSIGNED_SHORT_5_5_5_1:

+            case GL_FLOAT:

+            case GL_HALF_FLOAT_OES:

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+        case GL_BGRA_EXT:

+            switch(type)

+            {

+            case GL_UNSIGNED_BYTE:

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+            break;

+        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:  // error cases for compressed textures are handled below

+        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+            break;

+		case GL_DEPTH_COMPONENT:

+			switch(type)

+			{

+			case GL_UNSIGNED_SHORT:

+			case GL_UNSIGNED_INT:

+				break;

+			default:

+				return error(GL_INVALID_ENUM);

+			}

+			break;

+		case GL_DEPTH_STENCIL_OES:

+			switch(type)

+			{

+			case GL_UNSIGNED_INT_24_8_OES:

+				break;

+			default:

+				return error(GL_INVALID_ENUM);

+			}

+			break;

+        default:

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(border != 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            switch(target)

+            {

+              case GL_TEXTURE_2D:

+                if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||

+                   height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:

+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:

+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

+                if(width != height)

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+

+                if(width > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||

+                   height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+              default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||

+               format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||

+			   format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE ||

+			   format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)

+            {

+                if(S3TC_SUPPORT)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+            }

+			

+            if(target == GL_TEXTURE_2D)

+            {

+                gl::Texture2D *texture = context->getTexture2D();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+                texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels);

+            }

+            else

+            {

+                gl::TextureCubeMap *texture = context->getTextureCubeMap();

+

+                if(!texture)

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+

+				texture->setImage(target, level, width, height, format, type, context->getUnpackAlignment(), pixels);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat param = %f)", target, pname, param);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *texture;

+

+            switch(target)

+            {

+            case GL_TEXTURE_2D:

+                texture = context->getTexture2D();

+                break;

+            case GL_TEXTURE_CUBE_MAP:

+                texture = context->getTextureCubeMap();

+                break;

+            case GL_TEXTURE_EXTERNAL_OES:

+                texture = context->getTextureExternal();

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            switch(pname)

+            {

+            case GL_TEXTURE_WRAP_S:

+                if(!texture->setWrapS((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_WRAP_T:

+                if(!texture->setWrapT((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_MIN_FILTER:

+                if(!texture->setMinFilter((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_MAG_FILTER:

+                if(!texture->setMagFilter((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_MAX_ANISOTROPY_EXT:

+                if(!texture->setMaxAnisotropy(param))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)

+{

+    glTexParameterf(target, pname, *params);

+}

+

+void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)

+{

+    TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture *texture;

+

+            switch(target)

+            {

+            case GL_TEXTURE_2D:

+                texture = context->getTexture2D();

+                break;

+            case GL_TEXTURE_CUBE_MAP:

+                texture = context->getTextureCubeMap();

+                break;

+            case GL_TEXTURE_EXTERNAL_OES:

+                  texture = context->getTextureExternal();

+                  break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+

+            switch(pname)

+            {

+            case GL_TEXTURE_WRAP_S:

+                if(!texture->setWrapS((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_WRAP_T:

+                if(!texture->setWrapT((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_MIN_FILTER:

+                if(!texture->setMinFilter((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+            case GL_TEXTURE_MAG_FILTER:

+                if(!texture->setMagFilter((GLenum)param))

+                {

+                    return error(GL_INVALID_ENUM);

+                }

+                break;

+			case GL_TEXTURE_MAX_ANISOTROPY_EXT:

+                if(!texture->setMaxAnisotropy((GLfloat)param))

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+                break;

+            default:

+                return error(GL_INVALID_ENUM);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params)

+{

+    glTexParameteri(target, pname, *params);

+}

+

+void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                               GLenum format, GLenum type, const GLvoid* pixels)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "

+          "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "

+          "const GLvoid* pixels = 0x%0.8p)",

+           target, level, xoffset, yoffset, width, height, format, type, pixels);

+

+    try

+    {

+        if(!gl::IsTextureTarget(target))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(!gl::CheckTextureFormatType(format, type))

+        {

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(width == 0 || height == 0 || pixels == NULL)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)

+            {

+                return error(GL_INVALID_VALUE);

+            }

+

+            if(target == GL_TEXTURE_2D)

+            {

+                gl::Texture2D *texture = context->getTexture2D();

+

+                if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))

+				{

+					texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);

+				}

+            }

+            else if(gl::IsCubemapTextureTarget(target))

+            {

+                gl::TextureCubeMap *texture = context->getTextureCubeMap();

+				

+				if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))

+				{

+					texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);

+				}

+            }

+            else

+            {

+                UNREACHABLE();

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform1f(GLint location, GLfloat x)

+{

+    glUniform1fv(location, 1, &x);

+}

+

+void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform1fv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform1i(GLint location, GLint x)

+{

+    glUniform1iv(location, 1, &x);

+}

+

+void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform1iv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y)

+{

+    GLfloat xy[2] = {x, y};

+

+    glUniform2fv(location, 1, (GLfloat*)&xy);

+}

+

+void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+        

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform2fv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y)

+{

+    GLint xy[4] = {x, y};

+

+    glUniform2iv(location, 1, (GLint*)&xy);

+}

+

+void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform2iv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)

+{

+    GLfloat xyz[3] = {x, y, z};

+

+    glUniform3fv(location, 1, (GLfloat*)&xyz);

+}

+

+void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform3fv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z)

+{

+    GLint xyz[3] = {x, y, z};

+

+    glUniform3iv(location, 1, (GLint*)&xyz);

+}

+

+void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform3iv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)

+{

+    GLfloat xyzw[4] = {x, y, z, w};

+

+    glUniform4fv(location, 1, (GLfloat*)&xyzw);

+}

+

+void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform4fv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)

+{

+    GLint xyzw[4] = {x, y, z, w};

+

+    glUniform4iv(location, 1, (GLint*)&xyzw);

+}

+

+void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);

+

+    try

+    {

+        if(count < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniform4iv(location, count, v))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",

+          location, count, transpose, value);

+

+    try

+    {

+        if(count < 0 || transpose != GL_FALSE)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniformMatrix2fv(location, count, value))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",

+          location, count, transpose, value);

+

+    try

+    {

+        if(count < 0 || transpose != GL_FALSE)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniformMatrix3fv(location, count, value))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)

+{

+    TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",

+          location, count, transpose, value);

+

+    try

+    {

+        if(count < 0 || transpose != GL_FALSE)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(location == -1)

+        {

+            return;

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *program = context->getCurrentProgram();

+

+            if(!program)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            if(!program->setUniformMatrix4fv(location, count, value))

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glUseProgram(GLuint program)

+{

+    TRACE("(GLuint program = %d)", program);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject && program != 0)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            if(program != 0 && !programObject->isLinked())

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            context->useProgram(program);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glValidateProgram(GLuint program)

+{

+    TRACE("(GLuint program = %d)", program);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Program *programObject = context->getProgram(program);

+

+            if(!programObject)

+            {

+                if(context->getShader(program))

+                {

+                    return error(GL_INVALID_OPERATION);

+                }

+                else

+                {

+                    return error(GL_INVALID_VALUE);

+                }

+            }

+

+            programObject->validate();

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x)

+{

+    TRACE("(GLuint index = %d, GLfloat x = %f)", index, x);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { x, 0, 0, 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values)

+{

+    TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { values[0], 0, 0, 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)

+{

+    TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { x, y, 0, 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values)

+{

+    TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { values[0], values[1], 0, 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)

+{

+    TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { x, y, z, 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values)

+{

+    TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { values[0], values[1], values[2], 1 };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)

+{

+    TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            GLfloat vals[4] = { x, y, z, w };

+            context->setVertexAttrib(index, vals);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values)

+{

+    TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setVertexAttrib(index, values);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)

+{

+    TRACE("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "

+          "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)",

+          index, size, type, normalized, stride, ptr);

+

+    try

+    {

+        if(index >= gl::MAX_VERTEX_ATTRIBS)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(size < 1 || size > 4)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        switch(type)

+        {

+          case GL_BYTE:

+          case GL_UNSIGNED_BYTE:

+          case GL_SHORT:

+          case GL_UNSIGNED_SHORT:

+          case GL_FIXED:

+          case GL_FLOAT:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(stride < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)

+{

+    TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);

+

+    try

+    {

+        if(width < 0 || height < 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            context->setViewportParams(x, y, width, height);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,

+                                      GLbitfield mask, GLenum filter)

+{

+    TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "

+          "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "

+          "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",

+          srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);

+

+    try

+    {

+        switch(filter)

+        {

+          case GL_NEAREST:

+            break;

+          default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)

+        {

+            return error(GL_INVALID_VALUE);

+        }

+

+        if(srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)

+        {

+            ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");

+            return error(GL_INVALID_OPERATION);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            if(context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())

+            {

+                ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");

+                return error(GL_INVALID_OPERATION);

+            }

+

+            context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,

+                               GLint border, GLenum format, GLenum type, const GLvoid* pixels)

+{

+    TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "

+          "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "

+          "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",

+          target, level, internalformat, width, height, depth, border, format, type, pixels);

+

+    try

+    {

+        UNIMPLEMENTED();   // FIXME

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)

+{

+    TRACE("(GLenum target = 0x%X, GLeglImageOES image = 0x%0.8p)", target, image);

+

+    try

+    {

+        switch(target)

+        {

+        case GL_TEXTURE_EXTERNAL_OES:

+            break;

+        default:

+            return error(GL_INVALID_ENUM);

+        }

+

+        if(!image)

+        {

+            return error(GL_INVALID_OPERATION);

+        }

+

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::TextureExternal *texture = context->getTextureExternal();

+

+            if(!texture)

+            {

+                return error(GL_INVALID_OPERATION);

+            }

+

+            gl::Image *glImage = static_cast<gl::Image*>(image);

+

+            texture->setImage(glImage);

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+__eglMustCastToProperFunctionPointerType glGetProcAddress(const char *procname)

+{

+    struct Extension

+    {

+        const char *name;

+        __eglMustCastToProperFunctionPointerType address;

+    };

+

+    static const Extension glExtensions[] =

+    {

+        {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES},

+        {"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE},

+        {"glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)glRenderbufferStorageMultisampleANGLE},

+        {"glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)glDeleteFencesNV},

+        {"glGenFencesNV", (__eglMustCastToProperFunctionPointerType)glGenFencesNV},

+        {"glIsFenceNV", (__eglMustCastToProperFunctionPointerType)glIsFenceNV},

+        {"glTestFenceNV", (__eglMustCastToProperFunctionPointerType)glTestFenceNV},

+        {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV},

+        {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV},

+        {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV},

+		{"glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)glGetGraphicsResetStatusEXT},

+        {"glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)glReadnPixelsEXT},

+        {"glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformfvEXT},

+        {"glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformivEXT},

+		{"glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)glGenQueriesEXT},

+        {"glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)glDeleteQueriesEXT},

+        {"glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)glIsQueryEXT},

+        {"glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)glBeginQueryEXT},

+        {"glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)glEndQueryEXT},

+        {"glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryivEXT},

+        {"glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryObjectuivEXT},

+        {"glEGLImageTargetTexture2DOES", (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES}

+    };

+

+    for(int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)

+    {

+        if(strcmp(procname, glExtensions[ext].name) == 0)

+        {

+            return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;

+        }

+    }

+

+    return NULL;

+}

+

+void glBindTexImage(egl::Surface *surface)

+{

+    TRACE("(egl::Surface* surface = 0x%0.8p)",

+          surface);

+

+    try

+    {

+        gl::Context *context = gl::getContext();

+

+        if(context)

+        {

+            gl::Texture2D *textureObject = context->getTexture2D();

+

+            if(textureObject)

+            {

+                textureObject->bindTexImage(surface);

+            }

+        }

+    }

+    catch(std::bad_alloc&)

+    {

+        return error(GL_OUT_OF_MEMORY);

+    }

+}

+

+void GL_APIENTRY Register(const char *licenseKey)

+{

+	RegisterLicenseKey(licenseKey);

+}

+

+}

diff --git a/src/GLES2/libGLES_CM/libGLESv2.def b/src/GLES2/libGLES_CM/libGLESv2.def
new file mode 100644
index 0000000..bd087d3
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.def
@@ -0,0 +1,183 @@
+LIBRARY libGLESv2
+EXPORTS
+    glActiveTexture                 @1
+    glAttachShader                  @2
+    glBindAttribLocation            @3
+    glBindBuffer                    @4
+    glBindFramebuffer               @5
+    glBindRenderbuffer              @6
+    glBindTexture                   @7
+    glBlendColor                    @8
+    glBlendEquation                 @9
+    glBlendEquationSeparate         @10
+    glBlendFunc                     @11
+    glBlendFuncSeparate             @12
+    glBufferData                    @13
+    glBufferSubData                 @14
+    glCheckFramebufferStatus        @15
+    glClear                         @16
+    glClearColor                    @17
+    glClearDepthf                   @18
+    glClearStencil                  @19
+    glColorMask                     @20
+    glCompileShader                 @21
+    glCompressedTexImage2D          @22
+    glCompressedTexSubImage2D       @23
+    glCopyTexImage2D                @24
+    glCopyTexSubImage2D             @25
+    glCreateProgram                 @26
+    glCreateShader                  @27
+    glCullFace                      @28
+    glDeleteBuffers                 @29
+    glDeleteFramebuffers            @30
+    glDeleteProgram                 @32
+    glDeleteRenderbuffers           @33
+    glDeleteShader                  @34
+    glDeleteTextures                @31
+    glDepthFunc                     @36
+    glDepthMask                     @37
+    glDepthRangef                   @38
+    glDetachShader                  @35
+    glDisable                       @39
+    glDisableVertexAttribArray      @40
+    glDrawArrays                    @41
+    glDrawElements                  @42
+    glEnable                        @43
+    glEnableVertexAttribArray       @44
+    glFinish                        @45
+    glFlush                         @46
+    glFramebufferRenderbuffer       @47
+    glFramebufferTexture2D          @48
+    glFrontFace                     @49
+    glGenBuffers                    @50
+    glGenFramebuffers               @52
+    glGenRenderbuffers              @53
+    glGenTextures                   @54
+    glGenerateMipmap                @51
+    glGetActiveAttrib               @55
+    glGetActiveUniform              @56
+    glGetAttachedShaders            @57
+    glGetAttribLocation             @58
+    glGetBooleanv                   @59
+    glGetBufferParameteriv          @60
+    glGetError                      @61
+    glGetFloatv                     @62
+    glGetFramebufferAttachmentParameteriv   @63
+    glGetIntegerv                   @64
+    glGetProgramInfoLog             @66
+    glGetProgramiv                  @65
+    glGetRenderbufferParameteriv    @67
+    glGetShaderInfoLog              @69
+    glGetShaderPrecisionFormat      @70
+    glGetShaderSource               @71
+    glGetShaderiv                   @68
+    glGetString                     @72
+    glGetTexParameterfv             @73
+    glGetTexParameteriv             @74
+    glGetUniformLocation            @77
+    glGetUniformfv                  @75
+    glGetUniformiv                  @76
+    glGetVertexAttribPointerv       @80
+    glGetVertexAttribfv             @78
+    glGetVertexAttribiv             @79
+    glHint                          @81
+    glIsBuffer                      @82
+    glIsEnabled                     @83
+    glIsFramebuffer                 @84
+    glIsProgram                     @85
+    glIsRenderbuffer                @86
+    glIsShader                      @87
+    glIsTexture                     @88
+    glLineWidth                     @89
+    glLinkProgram                   @90
+    glPixelStorei                   @91
+    glPolygonOffset                 @92
+    glReadPixels                    @93
+    glReleaseShaderCompiler         @94
+    glRenderbufferStorage           @95
+    glSampleCoverage                @96
+    glScissor                       @97
+    glShaderBinary                  @98
+    glShaderSource                  @99
+    glStencilFunc                   @100
+    glStencilFuncSeparate           @101
+    glStencilMask                   @102
+    glStencilMaskSeparate           @103
+    glStencilOp                     @104
+    glStencilOpSeparate             @105
+    glTexImage2D                    @106
+    glTexParameterf                 @107
+    glTexParameterfv                @108
+    glTexParameteri                 @109
+    glTexParameteriv                @110
+    glTexSubImage2D                 @111
+    glUniform1f                     @112
+    glUniform1fv                    @113
+    glUniform1i                     @114
+    glUniform1iv                    @115
+    glUniform2f                     @116
+    glUniform2fv                    @117
+    glUniform2i                     @118
+    glUniform2iv                    @119
+    glUniform3f                     @120
+    glUniform3fv                    @121
+    glUniform3i                     @122
+    glUniform3iv                    @123
+    glUniform4f                     @124
+    glUniform4fv                    @125
+    glUniform4i                     @126
+    glUniform4iv                    @127
+    glUniformMatrix2fv              @128
+    glUniformMatrix3fv              @129
+    glUniformMatrix4fv              @130
+    glUseProgram                    @131
+    glValidateProgram               @132
+    glVertexAttrib1f                @133
+    glVertexAttrib1fv               @134
+    glVertexAttrib2f                @135
+    glVertexAttrib2fv               @136
+    glVertexAttrib3f                @137
+    glVertexAttrib3fv               @138
+    glVertexAttrib4f                @139
+    glVertexAttrib4fv               @140
+    glVertexAttribPointer           @141
+    glViewport                      @142
+
+    ; Extensions
+    glTexImage3DOES                 @143
+    glBlitFramebufferANGLE          @149
+    glRenderbufferStorageMultisampleANGLE @150
+    glDeleteFencesNV                @151
+    glFinishFenceNV                 @152
+    glGenFencesNV                   @153
+    glGetFenceivNV                  @154
+    glIsFenceNV                     @155
+    glSetFenceNV                    @156
+    glTestFenceNV                   @157
+    ;glGetTranslatedShaderSourceANGLE @159
+    ;glTexStorage2DEXT               @160
+    glGetGraphicsResetStatusEXT     @161
+    glReadnPixelsEXT                @162
+    glGetnUniformfvEXT              @163
+    glGetnUniformivEXT              @164
+	glGenQueriesEXT                 @165
+    glDeleteQueriesEXT              @166
+    glIsQueryEXT                    @167
+    glBeginQueryEXT                 @168
+    glEndQueryEXT                   @169
+    glGetQueryivEXT                 @170
+    glGetQueryObjectuivEXT          @171
+
+    ; EGL dependencies
+    glCreateContext                 @144
+    glDestroyContext                @145
+    glMakeCurrent                   @146
+    glGetCurrentContext             @147
+    glGetProcAddress                @148
+    glBindTexImage                  @158
+
+	createFrameBuffer               @172
+	createBackBuffer                @173
+	createDevice                    @174
+
+	Register
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/libGLESv2.rc b/src/GLES2/libGLES_CM/libGLESv2.rc
new file mode 100644
index 0000000..919c7ed
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include "../../common/Version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""../common/version.h""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "SwiftShader libGLESv2 Dynamic Link Library"
+            VALUE "FileVersion", VERSION_STRING
+            VALUE "InternalName", "libGLESv2"
+            VALUE "LegalCopyright", "Copyright (C) 2012 TransGaming Inc."
+            VALUE "OriginalFilename", "libGLESv2.dll"
+            VALUE "PrivateBuild", VERSION_STRING
+            VALUE "ProductName", "SwiftShader libGLESv2 Dynamic Link Library"
+            VALUE "ProductVersion", VERSION_STRING
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/src/GLES2/libGLES_CM/libGLESv2.vcxproj b/src/GLES2/libGLES_CM/libGLESv2.vcxproj
new file mode 100644
index 0000000..c833496
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.vcxproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Profile|Win32">

+      <Configuration>Profile</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{B5871A7A-968C-42E3-A33B-981E6F448E78}</ProjectGuid>

+    <RootNamespace>libGLESv2</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <CharacterSet>NotSet</CharacterSet>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <PlatformToolset>v120</PlatformToolset>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <CharacterSet>NotSet</CharacterSet>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <PlatformToolset>v120</PlatformToolset>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <CharacterSet>NotSet</CharacterSet>

+    <PlatformToolset>v120</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>

+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>

+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>

+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>

+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</IntDir>

+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>

+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">false</LinkIncremental>

+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>

+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>

+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>

+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>

+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>

+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>$(SolutionDir);$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <BrowseInformation>true</BrowseInformation>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+    <PostBuildEvent>

+      <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"

+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>

+    </PostBuildEvent>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <Optimization>Full</Optimization>

+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>

+      </DebugInformationFormat>

+      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <IntrinsicFunctions>false</IntrinsicFunctions>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>

+      <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+    <PostBuildEvent>

+      <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"

+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>

+    </PostBuildEvent>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">

+    <ClCompile>

+      <Optimization>Full</Optimization>

+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

+      <OmitFramePointers>false</OmitFramePointers>

+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <IntrinsicFunctions>false</IntrinsicFunctions>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>

+      <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+    <PostBuildEvent>

+      <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"

+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>

+    </PostBuildEvent>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="Buffer.cpp" />

+    <ClCompile Include="Context.cpp" />

+    <ClCompile Include="..\common\debug.cpp" />

+    <ClCompile Include="Device.cpp" />

+    <ClCompile Include="Fence.cpp" />

+    <ClCompile Include="Framebuffer.cpp" />

+    <ClCompile Include="HandleAllocator.cpp" />

+    <ClCompile Include="Image.cpp" />

+    <ClCompile Include="IndexDataManager.cpp" />

+    <ClCompile Include="libGLESv2.cpp" />

+    <ClCompile Include="main.cpp" />

+    <ClCompile Include="Program.cpp" />

+    <ClCompile Include="Query.cpp" />

+    <ClCompile Include="RefCountObject.cpp" />

+    <ClCompile Include="Renderbuffer.cpp" />

+    <ClCompile Include="ResourceManager.cpp" />

+    <ClCompile Include="Shader.cpp" />

+    <ClCompile Include="Texture.cpp" />

+    <ClCompile Include="utilities.cpp" />

+    <ClCompile Include="VertexDataManager.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\common\debug.h" />

+    <ClInclude Include="..\include\GLES2\gl2.h" />

+    <ClInclude Include="..\include\GLES2\gl2ext.h" />

+    <ClInclude Include="..\include\GLES2\gl2platform.h" />

+    <ClInclude Include="Buffer.h" />

+    <ClInclude Include="Context.h" />

+    <ClInclude Include="Device.hpp" />

+    <ClInclude Include="Fence.h" />

+    <ClInclude Include="Framebuffer.h" />

+    <ClInclude Include="HandleAllocator.h" />

+    <ClInclude Include="Image.hpp" />

+    <ClInclude Include="IndexDataManager.h" />

+    <ClInclude Include="main.h" />

+    <ClInclude Include="mathutil.h" />

+    <ClInclude Include="Program.h" />

+    <ClInclude Include="Query.h" />

+    <ClInclude Include="RefCountObject.h" />

+    <ClInclude Include="Renderbuffer.h" />

+    <ClInclude Include="resource.h" />

+    <ClInclude Include="ResourceManager.h" />

+    <ClInclude Include="Shader.h" />

+    <ClInclude Include="Texture.h" />

+    <ClInclude Include="utilities.h" />

+    <ClInclude Include="VertexDataManager.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="libGLESv2.def" />

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="libGLESv2.rc" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\SwiftShader\SwiftShader.vcxproj">

+      <Project>{7b02cb19-4cdf-4f79-bc9b-7f3f6164a003}</Project>

+      <Private>true</Private>

+      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>

+      <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>

+      <LinkLibraryDependencies>true</LinkLibraryDependencies>

+      <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>

+    </ProjectReference>

+    <ProjectReference Include="..\compiler\Compiler.vcxproj">

+      <Project>{5b3a6db8-1e7e-40d7-92b9-da8aae619fad}</Project>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters b/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters
new file mode 100644
index 0000000..91125de
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="Buffer.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Context.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="..\common\debug.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Fence.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Framebuffer.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="HandleAllocator.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="IndexDataManager.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="libGLESv2.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Program.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="RefCountObject.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Renderbuffer.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ResourceManager.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Shader.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Texture.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="utilities.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="VertexDataManager.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Device.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Image.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Query.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="Buffer.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Context.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Fence.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Framebuffer.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="HandleAllocator.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="IndexDataManager.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="main.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="mathutil.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Program.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="RefCountObject.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Renderbuffer.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="resource.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ResourceManager.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Shader.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Texture.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="utilities.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="VertexDataManager.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Device.hpp">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Image.hpp">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\include\GLES2\gl2.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\include\GLES2\gl2ext.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\include\GLES2\gl2platform.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Query.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\common\debug.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="libGLESv2.rc" />

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="libGLESv2.def" />

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/main.cpp b/src/GLES2/libGLES_CM/main.cpp
new file mode 100644
index 0000000..9ddca97
--- /dev/null
+++ b/src/GLES2/libGLES_CM/main.cpp
@@ -0,0 +1,189 @@
+// 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.

+//

+

+// main.cpp: DLL entry point and management of thread-local data.

+

+#include "main.h"

+

+#include "Framebuffer.h"

+#include "libEGL/Surface.h"

+#include "Common/Thread.hpp"

+#include "common/debug.h"

+

+static sw::Thread::LocalStorageKey currentTLS = TLS_OUT_OF_INDEXES;

+

+#if !defined(_MSC_VER)

+#define CONSTRUCTOR __attribute__((constructor))

+#define DESTRUCTOR __attribute__((destructor))

+#else

+#define CONSTRUCTOR

+#define DESTRUCTOR

+#endif

+

+static void glAttachThread()

+{

+    TRACE("()");

+

+	gl::Current *current = new gl::Current;

+

+    if(current)

+    {

+		sw::Thread::setLocalStorage(currentTLS, current);

+

+        current->context = NULL;

+        current->display = NULL;

+    }

+}

+

+static void glDetachThread()

+{

+    TRACE("()");

+

+	gl::Current *current = (gl::Current*)sw::Thread::getLocalStorage(currentTLS);

+

+    if(current)

+    {

+        delete current;

+    }

+}

+

+CONSTRUCTOR static bool glAttachProcess()

+{

+    TRACE("()");

+

+	currentTLS = sw::Thread::allocateLocalStorageKey();

+

+    if(currentTLS == TLS_OUT_OF_INDEXES)

+    {

+        return false;

+    }

+

+    glAttachThread();

+

+    return true;

+}

+

+DESTRUCTOR static void glDetachProcess()

+{

+    TRACE("()");

+

+	glDetachThread();

+

+    sw::Thread::freeLocalStorageKey(currentTLS);

+}

+

+#if defined(_WIN32)

+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)

+{

+    switch(reason)

+    {

+    case DLL_PROCESS_ATTACH:

+        return glAttachProcess();

+        break;

+    case DLL_THREAD_ATTACH:

+        glAttachThread();

+        break;

+    case DLL_THREAD_DETACH:

+        glDetachThread();

+        break;

+    case DLL_PROCESS_DETACH:

+        glDetachProcess();

+        break;

+    default:

+        break;

+    }

+

+    return TRUE;

+}

+#endif

+

+namespace gl

+{

+static gl::Current *getCurrent(void)

+{

+	Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS);

+

+	if(!current)

+	{

+		glAttachThread();

+	}

+

+	return (Current*)sw::Thread::getLocalStorage(currentTLS);

+}

+

+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)

+{

+    Current *current = getCurrent();

+

+    current->context = context;

+    current->display = display;

+

+    if(context && display && surface)

+    {

+        context->makeCurrent(display, surface);

+    }

+}

+

+Context *getContext()

+{

+    Current *current = getCurrent();

+

+    return current->context;

+}

+

+egl::Display *getDisplay()

+{

+    Current *current = getCurrent();

+

+    return current->display;

+}

+

+Device *getDevice()

+{

+    egl::Display *display = getDisplay();

+

+    return display->getDevice();

+}

+}

+

+// Records an error code

+void error(GLenum errorCode)

+{

+    gl::Context *context = gl::getContext();

+

+    if(context)

+    {

+        switch(errorCode)

+        {

+        case GL_INVALID_ENUM:

+            context->recordInvalidEnum();

+            TRACE("\t! Error generated: invalid enum\n");

+            break;

+        case GL_INVALID_VALUE:

+            context->recordInvalidValue();

+            TRACE("\t! Error generated: invalid value\n");

+            break;

+        case GL_INVALID_OPERATION:

+            context->recordInvalidOperation();

+            TRACE("\t! Error generated: invalid operation\n");

+            break;

+        case GL_OUT_OF_MEMORY:

+            context->recordOutOfMemory();

+            TRACE("\t! Error generated: out of memory\n");

+            break;

+        case GL_INVALID_FRAMEBUFFER_OPERATION:

+            context->recordInvalidFramebufferOperation();

+            TRACE("\t! Error generated: invalid framebuffer operation\n");

+            break;

+        default: UNREACHABLE();

+        }

+    }

+}

diff --git a/src/GLES2/libGLES_CM/main.h b/src/GLES2/libGLES_CM/main.h
new file mode 100644
index 0000000..fdb0dc0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/main.h
@@ -0,0 +1,52 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBGLESV2_MAIN_H_
+#define LIBGLESV2_MAIN_H_
+
+#include "Context.h"
+#include "Device.hpp"
+#include "common/debug.h"
+#include "libEGL/Display.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace gl
+{
+	struct Current
+	{
+		Context *context;
+		egl::Display *display;
+	};
+
+	void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface);
+
+	Context *getContext();
+	egl::Display *getDisplay();
+
+	Device *getDevice();
+}
+
+void error(GLenum errorCode);
+
+template<class T>
+const T &error(GLenum errorCode, const T &returnValue)
+{
+    error(errorCode);
+
+    return returnValue;
+}
+
+#endif   // LIBGLESV2_MAIN_H_
diff --git a/src/GLES2/libGLES_CM/mathutil.h b/src/GLES2/libGLES_CM/mathutil.h
new file mode 100644
index 0000000..9955fb2
--- /dev/null
+++ b/src/GLES2/libGLES_CM/mathutil.h
@@ -0,0 +1,79 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 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.
+//
+
+// mathutil.h: Math and bit manipulation functions.
+
+#ifndef LIBGLESV2_MATHUTIL_H_
+#define LIBGLESV2_MATHUTIL_H_
+
+#include "common/debug.h"
+
+#include <math.h>
+
+namespace gl
+{
+inline bool isPow2(int x)
+{
+    return (x & (x - 1)) == 0 && (x != 0);
+}
+
+inline int log2(int x)
+{
+    int r = 0;
+    while((x >> r) > 1) r++;
+    return r;
+}
+
+inline unsigned int ceilPow2(unsigned int x)
+{
+    if(x != 0) x--;
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    x |= x >> 16;
+    x++;
+
+    return x;
+}
+
+template<typename T, typename MIN, typename MAX>
+inline T clamp(T x, MIN min, MAX max)
+{
+    return x < min ? min : (x > max ? max : x);
+}
+
+inline float clamp01(float x)
+{
+    return clamp(x, 0.0f, 1.0f);
+}
+
+template<const int n>
+inline unsigned int unorm(float x)
+{
+    const unsigned int max = 0xFFFFFFFF >> (32 - n);
+
+    if(x > 1)
+    {
+        return max;
+    }
+    else if(x < 0)
+    {
+        return 0;
+    }
+    else
+    {
+        return (unsigned int)(max * x + 0.5f);
+    }
+}
+}
+
+#endif   // LIBGLESV2_MATHUTIL_H_
diff --git a/src/GLES2/libGLES_CM/resource.h b/src/GLES2/libGLES_CM/resource.h
new file mode 100644
index 0000000..39adaad
--- /dev/null
+++ b/src/GLES2/libGLES_CM/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libGLESv2.rc
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/src/GLES2/libGLES_CM/utilities.cpp b/src/GLES2/libGLES_CM/utilities.cpp
new file mode 100644
index 0000000..c0004bf
--- /dev/null
+++ b/src/GLES2/libGLES_CM/utilities.cpp
@@ -0,0 +1,854 @@
+// 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.

+//

+

+// utilities.cpp: Conversion functions and other utility routines.

+

+#include "utilities.h"

+

+#include "mathutil.h"

+#include "Context.h"

+#include "common/debug.h"

+

+#include <limits>

+#include <stdio.h>

+

+namespace gl

+{

+	int UniformComponentCount(GLenum type)

+	{

+		switch(type)

+		{

+		case GL_BOOL:

+		case GL_FLOAT:

+		case GL_INT:

+		case GL_SAMPLER_2D:

+		case GL_SAMPLER_CUBE:

+        case GL_SAMPLER_EXTERNAL_OES:

+			return 1;

+		case GL_BOOL_VEC2:

+		case GL_FLOAT_VEC2:

+		case GL_INT_VEC2:

+			return 2;

+		case GL_INT_VEC3:

+		case GL_FLOAT_VEC3:

+		case GL_BOOL_VEC3:

+			return 3;

+		case GL_BOOL_VEC4:

+		case GL_FLOAT_VEC4:

+		case GL_INT_VEC4:

+		case GL_FLOAT_MAT2:

+			return 4;

+		case GL_FLOAT_MAT3:

+			return 9;

+		case GL_FLOAT_MAT4:

+			return 16;

+		default:

+			UNREACHABLE();

+		}

+

+		return 0;

+	}

+

+	GLenum UniformComponentType(GLenum type)

+	{

+		switch(type)

+		{

+		case GL_BOOL:

+		case GL_BOOL_VEC2:

+		case GL_BOOL_VEC3:

+		case GL_BOOL_VEC4:

+			return GL_BOOL;

+		case GL_FLOAT:

+		case GL_FLOAT_VEC2:

+		case GL_FLOAT_VEC3:

+		case GL_FLOAT_VEC4:

+		case GL_FLOAT_MAT2:

+		case GL_FLOAT_MAT3:

+		case GL_FLOAT_MAT4:

+			return GL_FLOAT;

+		case GL_INT:

+		case GL_SAMPLER_2D:

+		case GL_SAMPLER_CUBE:

+        case GL_SAMPLER_EXTERNAL_OES:

+		case GL_INT_VEC2:

+		case GL_INT_VEC3:

+		case GL_INT_VEC4:

+			return GL_INT;

+		default:

+			UNREACHABLE();

+		}

+

+		return GL_NONE;

+	}

+

+	size_t UniformTypeSize(GLenum type)

+	{

+		switch(type)

+		{

+		case GL_BOOL:  return sizeof(GLboolean);

+		case GL_FLOAT: return sizeof(GLfloat);

+		case GL_INT:   return sizeof(GLint);

+		}

+

+		return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(type);

+	}

+

+	int VariableRowCount(GLenum type)

+	{

+		switch(type)

+		{

+		case GL_NONE:

+			return 0;

+		case GL_BOOL:

+		case GL_FLOAT:

+		case GL_INT:

+		case GL_BOOL_VEC2:

+		case GL_FLOAT_VEC2:

+		case GL_INT_VEC2:

+		case GL_INT_VEC3:

+		case GL_FLOAT_VEC3:

+		case GL_BOOL_VEC3:

+		case GL_BOOL_VEC4:

+		case GL_FLOAT_VEC4:

+		case GL_INT_VEC4:

+		case GL_SAMPLER_2D:

+		case GL_SAMPLER_CUBE:

+        case GL_SAMPLER_EXTERNAL_OES:

+			return 1;

+		case GL_FLOAT_MAT2:

+			return 2;

+		case GL_FLOAT_MAT3:

+			return 3;

+		case GL_FLOAT_MAT4:

+			return 4;

+		default:

+			UNREACHABLE();

+		}

+

+		return 0;

+	}

+

+	int VariableColumnCount(GLenum type)

+	{

+		switch(type)

+		{

+		case GL_NONE:

+			return 0;

+		case GL_BOOL:

+		case GL_FLOAT:

+		case GL_INT:

+			return 1;

+		case GL_BOOL_VEC2:

+		case GL_FLOAT_VEC2:

+		case GL_INT_VEC2:

+		case GL_FLOAT_MAT2:

+			return 2;

+		case GL_INT_VEC3:

+		case GL_FLOAT_VEC3:

+		case GL_BOOL_VEC3:

+		case GL_FLOAT_MAT3:

+			return 3;

+		case GL_BOOL_VEC4:

+		case GL_FLOAT_VEC4:

+		case GL_INT_VEC4:

+		case GL_FLOAT_MAT4:

+			return 4;

+		default:

+			UNREACHABLE();

+		}

+

+		return 0;

+	}

+

+	int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)

+	{

+		ASSERT(allocationSize <= bitsSize);

+

+		unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize);

+

+		for(unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)

+		{

+			if((*bits & mask) == 0)

+			{

+				*bits |= mask;

+				return i;

+			}

+

+			mask <<= 1;

+		}

+

+		return -1;

+	}

+

+	GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment)

+	{

+		ASSERT(alignment > 0 && isPow2(alignment));

+

+		GLsizei rawPitch = ComputePixelSize(format, type) * width;

+		return (rawPitch + alignment - 1) & ~(alignment - 1);

+	}

+

+	GLsizei ComputeCompressedPitch(GLsizei width, GLenum format)

+	{

+		return ComputeCompressedSize(width, 1, format);

+	}

+

+	GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)

+	{

+		switch(format)

+		{

+		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:

+		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:

+			return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);

+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:

+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:

+			return 16 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);

+		default:

+			return 0;

+		}

+	}

+

+	bool IsCompressed(GLenum format)

+	{

+		if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||

+		   format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||

+		   format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE ||

+		   format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)

+		{

+			return true;

+		}

+		else

+		{

+			return false;

+		}

+	}

+

+	bool IsDepthTexture(GLenum format)

+	{

+		if(format == GL_DEPTH_COMPONENT ||

+		   format == GL_DEPTH_STENCIL_OES)

+		{

+			return true;

+		}

+

+		return false;

+	}

+

+	bool IsStencilTexture(GLenum format)

+	{

+		if(format == GL_STENCIL_INDEX ||

+		   format == GL_DEPTH_STENCIL_OES)

+		{

+			return true;

+		}

+

+		return false;

+	}

+

+	// Returns the size, in bytes, of a single texel in an Image

+	int ComputePixelSize(GLenum format, GLenum type)

+	{

+		switch(type)

+		{

+		case GL_UNSIGNED_BYTE:

+			switch(format)

+			{

+			case GL_ALPHA:           return sizeof(unsigned char);

+			case GL_LUMINANCE:       return sizeof(unsigned char);

+			case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;

+			case GL_RGB:             return sizeof(unsigned char) * 3;

+			case GL_RGBA:            return sizeof(unsigned char) * 4;

+			case GL_BGRA_EXT:        return sizeof(unsigned char) * 4;

+			default: UNREACHABLE();

+			}

+			break;

+		case GL_UNSIGNED_SHORT_4_4_4_4:

+		case GL_UNSIGNED_SHORT_5_5_5_1:

+		case GL_UNSIGNED_SHORT_5_6_5:

+		case GL_UNSIGNED_SHORT:

+			return sizeof(unsigned short);

+		case GL_UNSIGNED_INT:

+		case GL_UNSIGNED_INT_24_8_OES:

+			return sizeof(unsigned int);

+		case GL_FLOAT:

+			switch(format)

+			{

+			case GL_ALPHA:           return sizeof(float);

+			case GL_LUMINANCE:       return sizeof(float);

+			case GL_LUMINANCE_ALPHA: return sizeof(float) * 2;

+			case GL_RGB:             return sizeof(float) * 3;

+			case GL_RGBA:            return sizeof(float) * 4;

+			default: UNREACHABLE();

+			}

+			break;

+		case GL_HALF_FLOAT_OES:

+			switch(format)

+			{

+			case GL_ALPHA:           return sizeof(unsigned short);

+			case GL_LUMINANCE:       return sizeof(unsigned short);

+			case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2;

+			case GL_RGB:             return sizeof(unsigned short) * 3;

+			case GL_RGBA:            return sizeof(unsigned short) * 4;

+			default: UNREACHABLE();

+			}

+			break;

+		default: UNREACHABLE();

+		}

+

+		return 0;

+	}

+

+	bool IsCubemapTextureTarget(GLenum target)

+	{

+		return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);

+	}

+

+	int CubeFaceIndex(GLenum cubeFace)

+	{

+		switch(cubeFace)

+		{

+		case GL_TEXTURE_CUBE_MAP:

+		case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return 0;

+		case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: return 1;

+		case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: return 2;

+		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: return 3;

+		case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: return 4;

+		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return 5;

+		default: UNREACHABLE(); return 0;

+		}

+	}

+

+	bool IsTextureTarget(GLenum target)

+	{

+		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);

+	}

+

+	// Verify that format/type are one of the combinations from table 3.4.

+	bool CheckTextureFormatType(GLenum format, GLenum type)

+	{

+		switch(type)

+		{

+		case GL_UNSIGNED_BYTE:

+			switch(format)

+			{

+			case GL_RGBA:

+			case GL_BGRA_EXT:

+			case GL_RGB:

+			case GL_ALPHA:

+			case GL_LUMINANCE:

+			case GL_LUMINANCE_ALPHA:

+				return true;

+			default:

+				return false;

+			}

+		case GL_FLOAT:

+		case GL_HALF_FLOAT_OES:

+			switch(format)

+			{

+			case GL_RGBA:

+			case GL_RGB:

+			case GL_ALPHA:

+			case GL_LUMINANCE:

+			case GL_LUMINANCE_ALPHA:

+				return true;

+			default:

+				return false;

+			}

+		case GL_UNSIGNED_SHORT_4_4_4_4:

+		case GL_UNSIGNED_SHORT_5_5_5_1:

+			return (format == GL_RGBA);

+		case GL_UNSIGNED_SHORT_5_6_5:

+			return (format == GL_RGB);

+		case GL_UNSIGNED_INT:

+			return (format == GL_DEPTH_COMPONENT);

+		case GL_UNSIGNED_INT_24_8_OES:

+			return (format == GL_DEPTH_STENCIL_OES);

+		default:

+			return false;

+		}

+	}

+

+	bool IsColorRenderable(GLenum internalformat)

+	{

+		switch(internalformat)

+		{

+		case GL_RGBA4:

+		case GL_RGB5_A1:

+		case GL_RGB565:

+		case GL_RGB8_OES:

+		case GL_RGBA8_OES:

+			return true;

+		case GL_DEPTH_COMPONENT16:

+		case GL_STENCIL_INDEX8:

+		case GL_DEPTH24_STENCIL8_OES:

+			return false;

+		default:

+			UNIMPLEMENTED();

+		}

+

+		return false;

+	}

+

+	bool IsDepthRenderable(GLenum internalformat)

+	{

+		switch(internalformat)

+		{

+		case GL_DEPTH_COMPONENT16:

+		case GL_DEPTH24_STENCIL8_OES:

+			return true;

+		case GL_STENCIL_INDEX8:

+		case GL_RGBA4:

+		case GL_RGB5_A1:

+		case GL_RGB565:

+		case GL_RGB8_OES:

+		case GL_RGBA8_OES:

+			return false;

+		default:

+			UNIMPLEMENTED();

+		}

+

+		return false;

+	}

+

+	bool IsStencilRenderable(GLenum internalformat)

+	{

+		switch(internalformat)

+		{

+		case GL_STENCIL_INDEX8:

+		case GL_DEPTH24_STENCIL8_OES:

+			return true;

+		case GL_RGBA4:

+		case GL_RGB5_A1:

+		case GL_RGB565:

+		case GL_RGB8_OES:

+		case GL_RGBA8_OES:

+		case GL_DEPTH_COMPONENT16:

+			return false;

+		default:

+			UNIMPLEMENTED();

+		}

+

+		return false;

+	}

+}

+

+namespace es2sw

+{

+	sw::DepthCompareMode ConvertDepthComparison(GLenum comparison)

+	{

+		switch(comparison)

+		{

+		case GL_NEVER:    return sw::DEPTH_NEVER;

+		case GL_ALWAYS:   return sw::DEPTH_ALWAYS;

+		case GL_LESS:     return sw::DEPTH_LESS;

+		case GL_LEQUAL:   return sw::DEPTH_LESSEQUAL;

+		case GL_EQUAL:    return sw::DEPTH_EQUAL;

+		case GL_GREATER:  return sw::DEPTH_GREATER;

+		case GL_GEQUAL:   return sw::DEPTH_GREATEREQUAL;

+		case GL_NOTEQUAL: return sw::DEPTH_NOTEQUAL;

+		default: UNREACHABLE();

+		}

+

+		return sw::DEPTH_ALWAYS;

+	}

+

+	sw::StencilCompareMode ConvertStencilComparison(GLenum comparison)

+	{

+		switch(comparison)

+		{

+		case GL_NEVER:    return sw::STENCIL_NEVER;

+		case GL_ALWAYS:   return sw::STENCIL_ALWAYS;

+		case GL_LESS:     return sw::STENCIL_LESS;

+		case GL_LEQUAL:   return sw::STENCIL_LESSEQUAL;

+		case GL_EQUAL:    return sw::STENCIL_EQUAL;

+		case GL_GREATER:  return sw::STENCIL_GREATER;

+		case GL_GEQUAL:   return sw::STENCIL_GREATEREQUAL;

+		case GL_NOTEQUAL: return sw::STENCIL_NOTEQUAL;

+		default: UNREACHABLE();

+		}

+

+		return sw::STENCIL_ALWAYS;

+	}

+

+	sw::Color<float> ConvertColor(gl::Color color)

+	{

+		return sw::Color<float>(color.red, color.green, color.blue, color.alpha);

+	}

+

+	sw::BlendFactor ConvertBlendFunc(GLenum blend)

+	{

+		switch(blend)

+		{

+		case GL_ZERO:                     return sw::BLEND_ZERO;

+		case GL_ONE:                      return sw::BLEND_ONE;

+		case GL_SRC_COLOR:                return sw::BLEND_SOURCE;

+		case GL_ONE_MINUS_SRC_COLOR:      return sw::BLEND_INVSOURCE;

+		case GL_DST_COLOR:                return sw::BLEND_DEST;

+		case GL_ONE_MINUS_DST_COLOR:      return sw::BLEND_INVDEST;

+		case GL_SRC_ALPHA:                return sw::BLEND_SOURCEALPHA;

+		case GL_ONE_MINUS_SRC_ALPHA:      return sw::BLEND_INVSOURCEALPHA;

+		case GL_DST_ALPHA:                return sw::BLEND_DESTALPHA;

+		case GL_ONE_MINUS_DST_ALPHA:      return sw::BLEND_INVDESTALPHA;

+		case GL_CONSTANT_COLOR:           return sw::BLEND_CONSTANT;

+		case GL_ONE_MINUS_CONSTANT_COLOR: return sw::BLEND_INVCONSTANT;

+		case GL_CONSTANT_ALPHA:           return sw::BLEND_CONSTANTALPHA;

+		case GL_ONE_MINUS_CONSTANT_ALPHA: return sw::BLEND_INVCONSTANTALPHA;

+		case GL_SRC_ALPHA_SATURATE:       return sw::BLEND_SRCALPHASAT;

+		default: UNREACHABLE();

+		}

+

+		return sw::BLEND_ZERO;

+	}

+

+	sw::BlendOperation ConvertBlendOp(GLenum blendOp)

+	{

+		switch(blendOp)

+		{

+		case GL_FUNC_ADD:              return sw::BLENDOP_ADD;

+		case GL_FUNC_SUBTRACT:         return sw::BLENDOP_SUB;

+		case GL_FUNC_REVERSE_SUBTRACT: return sw::BLENDOP_INVSUB;

+		case GL_MIN_EXT:               return sw::BLENDOP_MIN;

+		case GL_MAX_EXT:               return sw::BLENDOP_MAX;

+		default: UNREACHABLE();

+		}

+

+		return sw::BLENDOP_ADD;

+	}

+

+	sw::StencilOperation ConvertStencilOp(GLenum stencilOp)

+	{

+		switch(stencilOp)

+		{

+		case GL_ZERO:      return sw::OPERATION_ZERO;

+		case GL_KEEP:      return sw::OPERATION_KEEP;

+		case GL_REPLACE:   return sw::OPERATION_REPLACE;

+		case GL_INCR:      return sw::OPERATION_INCRSAT;

+		case GL_DECR:      return sw::OPERATION_DECRSAT;

+		case GL_INVERT:    return sw::OPERATION_INVERT;

+		case GL_INCR_WRAP: return sw::OPERATION_INCR;

+		case GL_DECR_WRAP: return sw::OPERATION_DECR;

+		default: UNREACHABLE();

+		}

+

+		return sw::OPERATION_KEEP;

+	}

+

+	sw::AddressingMode ConvertTextureWrap(GLenum wrap)

+	{

+		switch(wrap)

+		{

+		case GL_REPEAT:            return sw::ADDRESSING_WRAP;

+		case GL_CLAMP_TO_EDGE:     return sw::ADDRESSING_CLAMP;

+		case GL_MIRRORED_REPEAT:   return sw::ADDRESSING_MIRROR;

+		default: UNREACHABLE();

+		}

+

+		return sw::ADDRESSING_WRAP;

+	}

+

+	sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace)

+	{

+		switch(cullFace)

+		{

+		case GL_FRONT:

+			return (frontFace == GL_CCW ? sw::CULL_CLOCKWISE : sw::CULL_COUNTERCLOCKWISE);

+		case GL_BACK:

+			return (frontFace == GL_CCW ? sw::CULL_COUNTERCLOCKWISE : sw::CULL_CLOCKWISE);

+		case GL_FRONT_AND_BACK:

+			return sw::CULL_NONE;   // culling will be handled during draw

+		default: UNREACHABLE();

+		}

+

+		return sw::CULL_COUNTERCLOCKWISE;

+	}

+

+	unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha)

+	{

+		return (red   ? 0x00000001 : 0) |

+			   (green ? 0x00000002 : 0) |

+			   (blue  ? 0x00000004 : 0) |

+			   (alpha ? 0x00000008 : 0);

+	}

+

+	sw::FilterType ConvertMagFilter(GLenum magFilter)

+	{

+		switch(magFilter)

+		{

+		case GL_NEAREST: return sw::FILTER_POINT;

+		case GL_LINEAR:  return sw::FILTER_LINEAR;

+		default: UNREACHABLE();

+		}

+

+		return sw::FILTER_POINT;

+	}

+

+	void ConvertMinFilter(GLenum texFilter, sw::FilterType *minFilter, sw::MipmapType *mipFilter, float maxAnisotropy)

+	{

+		switch(texFilter)

+		{

+		case GL_NEAREST:

+			*minFilter = sw::FILTER_POINT;

+			*mipFilter = sw::MIPMAP_NONE;

+			break;

+		case GL_LINEAR:

+			*minFilter = sw::FILTER_LINEAR;

+			*mipFilter = sw::MIPMAP_NONE;

+			break;

+		case GL_NEAREST_MIPMAP_NEAREST:

+			*minFilter = sw::FILTER_POINT;

+			*mipFilter = sw::MIPMAP_POINT;

+			break;

+		case GL_LINEAR_MIPMAP_NEAREST:

+			*minFilter = sw::FILTER_LINEAR;

+			*mipFilter = sw::MIPMAP_POINT;

+			break;

+		case GL_NEAREST_MIPMAP_LINEAR:

+			*minFilter = sw::FILTER_POINT;

+			*mipFilter = sw::MIPMAP_LINEAR;

+			break;

+		case GL_LINEAR_MIPMAP_LINEAR:

+			*minFilter = sw::FILTER_LINEAR;

+			*mipFilter = sw::MIPMAP_LINEAR;

+			break;

+		default:

+			*minFilter = sw::FILTER_POINT;

+			*mipFilter = sw::MIPMAP_NONE;

+			UNREACHABLE();

+		}

+

+		if(maxAnisotropy > 1.0f)

+		{

+			*minFilter = sw::FILTER_ANISOTROPIC;

+		}

+	}

+

+	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  gl::PrimitiveType &swPrimitiveType, int &primitiveCount)

+	{

+		switch(primitiveType)

+		{

+		case GL_POINTS:

+			swPrimitiveType = gl::DRAW_POINTLIST;

+			primitiveCount = elementCount;

+			break;

+		case GL_LINES:

+			swPrimitiveType = gl::DRAW_LINELIST;

+			primitiveCount = elementCount / 2;

+			break;

+		case GL_LINE_LOOP:

+			swPrimitiveType = gl::DRAW_LINELOOP;

+			primitiveCount = elementCount;

+			break;

+		case GL_LINE_STRIP:

+			swPrimitiveType = gl::DRAW_LINESTRIP;

+			primitiveCount = elementCount - 1;

+			break;

+		case GL_TRIANGLES:

+			swPrimitiveType = gl::DRAW_TRIANGLELIST;

+			primitiveCount = elementCount / 3;

+			break;

+		case GL_TRIANGLE_STRIP:

+			swPrimitiveType = gl::DRAW_TRIANGLESTRIP;

+			primitiveCount = elementCount - 2;

+			break;

+		case GL_TRIANGLE_FAN:

+			swPrimitiveType = gl::DRAW_TRIANGLEFAN;

+			primitiveCount = elementCount - 2;

+			break;

+		default:

+			return false;

+		}

+

+		return true;

+	}

+

+	sw::Format ConvertRenderbufferFormat(GLenum format)

+	{

+		switch(format)

+		{

+		case GL_RGBA4:

+		case GL_RGB5_A1:

+		case GL_RGBA8_OES:            return sw::FORMAT_A8R8G8B8;

+		case GL_RGB565:               return sw::FORMAT_R5G6B5;

+		case GL_RGB8_OES:             return sw::FORMAT_X8R8G8B8;

+		case GL_DEPTH_COMPONENT16:

+		case GL_STENCIL_INDEX8:       

+		case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;

+		default: UNREACHABLE();       return sw::FORMAT_A8R8G8B8;

+		}

+	}

+}

+

+namespace sw2es

+{

+	unsigned int GetStencilSize(sw::Format stencilFormat)

+	{

+		switch(stencilFormat)

+		{

+		case sw::FORMAT_D24FS8:

+		case sw::FORMAT_D24S8:

+		case sw::FORMAT_D32FS8_TEXTURE:

+			return 8;

+	//	case sw::FORMAT_D24X4S4:

+	//		return 4;

+	//	case sw::FORMAT_D15S1:

+	//		return 1;

+	//	case sw::FORMAT_D16_LOCKABLE:

+		case sw::FORMAT_D32:

+		case sw::FORMAT_D24X8:

+		case sw::FORMAT_D32F_LOCKABLE:

+		case sw::FORMAT_D16:

+			return 0;

+	//	case sw::FORMAT_D32_LOCKABLE:  return 0;

+	//	case sw::FORMAT_S8_LOCKABLE:   return 8;

+		default:

+			return 0;

+		}

+	}

+

+	unsigned int GetAlphaSize(sw::Format colorFormat)

+	{

+		switch(colorFormat)

+		{

+		case sw::FORMAT_A16B16G16R16F:

+			return 16;

+		case sw::FORMAT_A32B32G32R32F:

+			return 32;

+		case sw::FORMAT_A2R10G10B10:

+			return 2;

+		case sw::FORMAT_A8R8G8B8:

+			return 8;

+		case sw::FORMAT_A1R5G5B5:

+			return 1;

+		case sw::FORMAT_X8R8G8B8:

+		case sw::FORMAT_R5G6B5:

+			return 0;

+		default:

+			return 0;

+		}

+	}

+

+	unsigned int GetRedSize(sw::Format colorFormat)

+	{

+		switch(colorFormat)

+		{

+		case sw::FORMAT_A16B16G16R16F:

+			return 16;

+		case sw::FORMAT_A32B32G32R32F:

+			return 32;

+		case sw::FORMAT_A2R10G10B10:

+			return 10;

+		case sw::FORMAT_A8R8G8B8:

+		case sw::FORMAT_X8R8G8B8:

+			return 8;

+		case sw::FORMAT_A1R5G5B5:

+		case sw::FORMAT_R5G6B5:

+			return 5;

+		default:

+			return 0;

+		}

+	}

+

+	unsigned int GetGreenSize(sw::Format colorFormat)

+	{

+		switch(colorFormat)

+		{

+		case sw::FORMAT_A16B16G16R16F:

+			return 16;

+		case sw::FORMAT_A32B32G32R32F:

+			return 32;

+		case sw::FORMAT_A2R10G10B10:

+			return 10;

+		case sw::FORMAT_A8R8G8B8:

+		case sw::FORMAT_X8R8G8B8:

+			return 8;

+		case sw::FORMAT_A1R5G5B5:

+			return 5;

+		case sw::FORMAT_R5G6B5:

+			return 6;

+		default:

+			return 0;

+		}

+	}

+

+	unsigned int GetBlueSize(sw::Format colorFormat)

+	{

+		switch(colorFormat)

+		{

+		case sw::FORMAT_A16B16G16R16F:

+			return 16;

+		case sw::FORMAT_A32B32G32R32F:

+			return 32;

+		case sw::FORMAT_A2R10G10B10:

+			return 10;

+		case sw::FORMAT_A8R8G8B8:

+		case sw::FORMAT_X8R8G8B8:

+			return 8;

+		case sw::FORMAT_A1R5G5B5:

+		case sw::FORMAT_R5G6B5:

+			return 5;

+		default:

+			return 0;

+		}

+	}

+

+	unsigned int GetDepthSize(sw::Format depthFormat)

+	{

+		switch(depthFormat)

+		{

+	//	case sw::FORMAT_D16_LOCKABLE:   return 16;

+		case sw::FORMAT_D32:            return 32;

+	//	case sw::FORMAT_D15S1:          return 15;

+		case sw::FORMAT_D24S8:          return 24;

+		case sw::FORMAT_D24X8:          return 24;

+	//	case sw::FORMAT_D24X4S4:        return 24;

+		case sw::FORMAT_D16:            return 16;

+		case sw::FORMAT_D32F_LOCKABLE:  return 32;

+		case sw::FORMAT_D24FS8:         return 24;

+	//	case sw::FORMAT_D32_LOCKABLE:   return 32;

+	//	case sw::FORMAT_S8_LOCKABLE:    return 0;

+		case sw::FORMAT_D32FS8_TEXTURE: return 32;

+		default:                        return 0;

+		}

+	}

+

+	GLenum ConvertBackBufferFormat(sw::Format format)

+	{

+		switch(format)

+		{

+		case sw::FORMAT_A4R4G4B4: return GL_RGBA4;

+		case sw::FORMAT_A8R8G8B8: return GL_RGBA8_OES;

+		case sw::FORMAT_A1R5G5B5: return GL_RGB5_A1;

+		case sw::FORMAT_R5G6B5:   return GL_RGB565;

+		case sw::FORMAT_X8R8G8B8: return GL_RGB8_OES;

+		default:

+			UNREACHABLE();

+		}

+

+		return GL_RGBA4;

+	}

+

+	GLenum ConvertDepthStencilFormat(sw::Format format)

+	{

+		switch(format)

+		{

+		case sw::FORMAT_D16:

+		case sw::FORMAT_D24X8:

+		case sw::FORMAT_D32:

+			return GL_DEPTH_COMPONENT16;

+		case sw::FORMAT_D24S8:

+			return GL_DEPTH24_STENCIL8_OES;

+		default:

+			UNREACHABLE();

+		}

+

+		return GL_DEPTH24_STENCIL8_OES;

+	}

+}

diff --git a/src/GLES2/libGLES_CM/utilities.h b/src/GLES2/libGLES_CM/utilities.h
new file mode 100644
index 0000000..8475050
--- /dev/null
+++ b/src/GLES2/libGLES_CM/utilities.h
@@ -0,0 +1,86 @@
+// 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.

+//

+

+// utilities.h: Conversion functions and other utility routines.

+

+#ifndef LIBGLESV2_UTILITIES_H

+#define LIBGLESV2_UTILITIES_H

+

+#include "Device.hpp"

+#include "Image.hpp"

+#include "Texture.h"

+

+#define GL_APICALL

+#include <GLES2/gl2.h>

+#include <GLES2/gl2ext.h>

+

+#include <string>

+

+namespace gl

+{

+	struct Color;

+

+	int UniformComponentCount(GLenum type);

+	GLenum UniformComponentType(GLenum type);

+	size_t UniformTypeSize(GLenum type);

+	int VariableRowCount(GLenum type);

+	int VariableColumnCount(GLenum type);

+

+	int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);

+

+	int ComputePixelSize(GLenum format, GLenum type);

+	GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);

+	GLsizei ComputeCompressedPitch(GLsizei width, GLenum format);

+	GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);

+	bool IsCompressed(GLenum format);

+	bool IsDepthTexture(GLenum format);

+	bool IsStencilTexture(GLenum format);

+	bool IsCubemapTextureTarget(GLenum target);

+	int CubeFaceIndex(GLenum cubeTarget);

+	bool IsTextureTarget(GLenum target);

+	bool CheckTextureFormatType(GLenum format, GLenum type);

+

+	bool IsColorRenderable(GLenum internalformat);

+	bool IsDepthRenderable(GLenum internalformat);

+	bool IsStencilRenderable(GLenum internalformat);

+}

+

+namespace es2sw

+{

+	sw::DepthCompareMode ConvertDepthComparison(GLenum comparison);

+	sw::StencilCompareMode ConvertStencilComparison(GLenum comparison);

+	sw::Color<float> ConvertColor(gl::Color color);

+	sw::BlendFactor ConvertBlendFunc(GLenum blend);

+	sw::BlendOperation ConvertBlendOp(GLenum blendOp);

+	sw::StencilOperation ConvertStencilOp(GLenum stencilOp);

+	sw::AddressingMode ConvertTextureWrap(GLenum wrap);

+	sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace);

+	unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha);

+	sw::FilterType ConvertMagFilter(GLenum magFilter);

+	void ConvertMinFilter(GLenum texFilter, sw::FilterType *minFilter, sw::MipmapType *mipFilter, float maxAnisotropy);

+	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  gl::PrimitiveType &swPrimitiveType, int &primitiveCount);

+	sw::Format ConvertRenderbufferFormat(GLenum format);

+}

+

+namespace sw2es

+{

+	GLuint GetAlphaSize(sw::Format colorFormat);

+	GLuint GetRedSize(sw::Format colorFormat);

+	GLuint GetGreenSize(sw::Format colorFormat);

+	GLuint GetBlueSize(sw::Format colorFormat);

+	GLuint GetDepthSize(sw::Format depthFormat);

+	GLuint GetStencilSize(sw::Format stencilFormat);

+

+	GLenum ConvertBackBufferFormat(sw::Format format);

+	GLenum ConvertDepthStencilFormat(sw::Format format);

+}

+

+#endif  // LIBGLESV2_UTILITIES_H